diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+0.3.0.0
+-------
+<https://github.com/mstksg/auto/releases/tag/v0.3.0.0>
+
+*   **Control.Auto.Effects**: Breaking change: switched to strict `StateT`
+    and `WriterT`.
+*   **Control.Auto.Effects**: Added `readerA` and `writerA`, for convenience
+    in "creating" `Auto`s under `ReaderT` and `WriterT`; also added `stateA`
+    and `accumA` for completeness.
+
 0.2.0.6
 -------
 <https://github.com/mstksg/auto/releases/tag/v0.2.0.6>
diff --git a/auto.cabal b/auto.cabal
--- a/auto.cabal
+++ b/auto.cabal
@@ -1,5 +1,5 @@
 name:                auto
-version:             0.2.0.6
+version:             0.3.0.0
 synopsis:            Denotative, locally stateful programming DSL & platform
 description:         (Up to date documentation is maintained at
                      <https://mstksg.github.com/auto>)
diff --git a/src/Control/Auto/Effects.hs b/src/Control/Auto/Effects.hs
--- a/src/Control/Auto/Effects.hs
+++ b/src/Control/Auto/Effects.hs
@@ -26,47 +26,60 @@
   , arrMB
   , effectB
   , execB
-  -- * One-time effects
+  -- ** One-time effects
   , cache
   , execOnce
   , cache_
   , execOnce_
-  -- * Manipulating underlying monads
-  -- ** "Sealing off" monadic 'Auto's
-  , sealState
-  , sealState_
+  -- * Hoists
+  , hoistA
+  , generalizeA
+
+  -- * Specific underlying monads
+  -- $monads
+
+  -- ** 'ReaderT'
+  -- $reader
+  , runReaderA
   , sealReader
   , sealReader_
-  -- ** "Unrolling"/"reifying" monadic 'Auto's
-  , runStateA
-  , runReaderA
+  , readerA
+
+  -- ** 'WriterT'
+  -- $writer
+  , writerA
   , runWriterA
+
+  -- ** 'StateT'
+  -- $state
+  , sealState
+  , sealState_
+  , runStateA
+  , stateA
+  , accumA
+
+  -- ** 'Traversable'
   , runTraversableA
-  -- ** Hoists
-  , hoistA
-  , generalizeA
-  -- ** Working with IO
+
+  -- ** 'IO'
   , catchA
-  -- ** Constructing monadic 'Auto's from other monads
-  , fromState
-  , fromState_
   ) where
 
 import Control.Applicative
 import Control.Auto.Blip
-import Control.Exception
 import Control.Auto.Core
-import Control.Monad.Trans.Writer (WriterT, runWriterT)
 import Control.Auto.Generate
 import Control.Category
-import Control.Monad hiding       (mapM, mapM_)
-import Control.Monad.Trans.Reader (ReaderT, runReaderT)
-import Data.Monoid
-import Control.Monad.Trans.State  (StateT, runStateT)
+import Control.Exception
+import Control.Monad hiding              (mapM, mapM_)
+import Control.Monad.Trans.Reader        (ReaderT(ReaderT), runReaderT)
+import Control.Monad.Trans.State.Strict  (StateT(StateT), runStateT)
+import Control.Monad.Trans.Writer.Strict (WriterT(WriterT), runWriterT)
 import Data.Foldable
+import Data.Monoid
 import Data.Serialize
 import Data.Traversable
-import Prelude hiding             ((.), id, mapM, mapM_)
+import Prelude hiding                    ((.), id, mapM, mapM_)
 
 -- | The very first output executes a monadic action and uses the result as
 -- the output, ignoring all input.  From then on, it persistently outputs
@@ -199,116 +212,293 @@
 execB mx = perBlip (arrM $ \x -> mx >> return x)
 {-# INLINE execB #-}
 
--- | Takes an 'Auto' that works with underlying global, mutable state, and
--- "seals off the state" from the outside world.
+-- $monads
 --
--- An 'Auto (StateT s m) a b' maps a stream of 'a' to a stream of 'b', but
--- does so in the context of requiring an initial 's' to start, and
--- outputting a modified 's'.
+-- 'Auto's can be run in the context of an underlying monad; this means
+-- that, instead of just being a straight-up @[a] -> [b]@, pairing up each
+-- @a@ with a @b@, you can actually attach a "context" to the @b@-making
+-- process, in order to enrich your streaming logic with things like
+-- a global read-only environment, a global sink, or global mutable state.
+-- The main benefit is that these things all /compose/ like any other
+-- 'Auto'...they compose with '.', you can use 'Applicative', 'Arrow',
+-- etc., and they'll combine properly.
 --
--- Consider this example 'State' 'Auto':
+-- For the most part, a good general philosophy is to only have a "small
+-- part" of your program over a monad.  You might have a small region of
+-- your program that would benefit from having a global environment, a
+-- small region of your program that would benefit from having a sink, or
+-- a small program that would benefit from global mutable state.  Exercise
+-- good style and write maintainable code by limiting the effectful parts
+-- to the bare minimum essential, then using 'runReaderA', 'sealReader',
+-- 'runWriterA', 'sealStateA', etc. to "close off" or seal the effects, and
+-- use the 'Auto' like a normal one without effects.
 --
+-- In this section are combinators for working with specific underlying
+-- monads...and a little description on how each might be useful.  Remember
+-- to use them wisely!  Adding any underlying monad causes the complexity
+-- of reasoning with your code to go up (depending on which monad), so make
+-- sure that you get a real gain before using these!
+
+-- $reader
+-- 'Reader', or 'ReaderT' is probably one of the most useful underlying
+-- monads to work with.  Basically, instead of @[a] -> [b]@, you have @[a]
+-- -> r -> [b]@.  Generate @b@'s, but with an @r@ parameter you can always
+-- access.  In practice, you can use 'Reader' to hide a lot of boilerplate
+-- threading, add an extra "side input" channel, or compose 'Auto's with
+-- a /static guarantee/ that all 'Auto's composed will use the /same/ @r@
+-- environment.
+--
+-- Using 'effect', you have access to the environment:
+--
 -- @
--- foo :: Auto (State s) Int Int
--- foo = proc x -> do
---     execB (modify (+1)) . emitOn odd  -< x
---     execB (modify (*2)) . emitOn even -< x
---     st   <- effect get -< ()
---     sumX <- sumFrom 0  -< x
---     id    -< sumX + st
+-- 'effect' 'ask' :: 'MonadReader' r m => 'Auto' m a r
 -- @
 --
--- On every output, the "global" state is incremented if the input is odd
--- and doubled if the input is even.  The stream @st@ is always the value
--- of the global state at that point.  @sumX@ is the cumulative sum of the
--- inputs.  The final result is the sum of the value of the global state
--- and the cumulative sum.
+-- Which is an 'Auto' where the only thing it does is continually output
+-- the environment @r@.  You can throw this into any /proc/ block over
+-- 'Reader', and you have a way to bring your environment "into scope":
 --
--- In writing like this, you lose some of the denotative properties because
--- you are working with a global state that updates at every output.  You
--- have some benefit of now being able to work with global state, if that's
--- what you wanted I guess.
+-- @
+-- env <- 'effect' 'ask' -< ()
+-- @
 --
--- To "run" it, you could use 'streamAuto' to get a @'State' Int Int@:
 --
--- >>> let st = streamAuto foo [1..10] :: State Int Int
--- >>> runState st 5
--- ([  7, 15, 19, 36, 42, 75, 83,136,156,277], 222)
+-- For a use case example, you might have:
 --
--- (The starting state is 5 and the ending state after all of that is 222)
+-- @
+-- foo :: Auto m (Int, Database) Bool
+-- bar :: Auto m (Bool, Database) Int
+-- baz :: Auto m (Bool, Database) String
+-- @
 --
--- However, writing your entire program with global state is a bad bad
--- idea!  So, how can you get the "benefits" of having small parts like
--- @foo@ be written using 'State', and being able to use it in a program
--- with no global state?
+-- Where every 'Auto' use a @Database@ parameter to do their job...and it
+-- only makes sense when all of them are composed under the same
+-- @Database@.  You can use normal proc notation:
 --
--- Using 'sealState'!  Write the part of your program that would like
--- shared global state with 'State'...and compose it with the rest as if it
--- doesn't, locking it away!
+-- @
+-- full :: Auto m (Int, Database) String
+-- full = proc (inp, db) -> do
+--     fo <- foo -< (inp, db)
+--     br <- bar -< (fo, db)
+--     bz <- baz -< (fo, db)
+--     id -< replicate br bz
+-- @
 --
+-- Or, you can put them all under 'Reader' and have the parameters pass
+-- implicitly:
+--
 -- @
--- sealState       :: Auto (State s) a b -> s -> Auto' a b
--- sealState foo 5 :: Auto' Int Int
+-- fullR :: Auto (ReaderT Database m) Int String
+-- fullR = proc inp -> do
+--     fo <- readerA foo -< inp
+--     br <- readerA bar -< fo
+--     bz <- readerA baz -< fo
+--     id -< replicate br bz
 -- @
 --
+-- You can recover the original behavior of @full@ by using 'runReaderA' to
+-- "unroll" the implicit argument:
+--
 -- @
--- bar :: Auto' Int (Int, String)
+-- full' :: Auto m (Int, Database) String
+-- full' = runReaderA fullR
+-- @
+--
+-- You can also "seal" @fullR@ so that it always runs with the same
+-- @Database@ at every step using 'sealReader':
+--
+-- @
+-- fullSealed :: Database -> Auto m Int String
+-- fullSealed = sealReader fullR
+-- @
+--
+-- @fullSealed db@ will now assume that @foo@, @bar@, and @baz@ all get the
+-- same environment forever when they are stepped/streamed.
+
+-- | "Unrolls" the underlying 'ReaderT' of an 'Auto' into an 'Auto' that
+-- takes in the input "environment" every turn in addition to the normal
+-- input.
+--
+-- So you can use any @'ReaderT' r m@ as if it were an @m@.  Useful if you
+-- want to compose and create some isolated 'Auto's with access to an
+-- underlying environment, but not your entire program.
+--
+-- Also just simply useful as a convenient way to use an 'Auto' over
+-- 'Reader' with 'stepAuto' and friends.
+--
+-- When used with @'Reader' r@, it turns an @'Auto' ('Reader' r) a b@ into
+-- an @'Auto'' (a, r) b@.
+runReaderA :: Monad m
+           => Auto (ReaderT r m) a b    -- ^ 'Auto' run over global environment
+           -> Auto m (a, r) b           -- ^ 'Auto' receiving environments
+runReaderA a = mkAutoM (runReaderA <$> resumeAuto a)
+                       (saveAuto a)
+                     $ \(x, r) -> do
+                         (y, a') <- runReaderT (stepAuto a x) r
+                         return (y, runReaderA a')
+
+-- | Takes an 'Auto' that operates under the context of a read-only
+-- environment, an environment value, and turns it into a normal 'Auto'
+-- that always "sees" that value when it asks for one.
+--
+-- >>> let a   = effect ask :: Auto (Reader b) a b
+-- >>> let rdr = streamAuto' a [1..5] :: Reader b [b]
+-- >>> runReader rdr "hey"
+-- ["hey", "hey", "hey", "hey", "hey"]
+--
+-- Useful if you wanted to use it inside/composed with an 'Auto' that does
+-- not have a global environment:
+--
+-- @
+-- bar :: Auto' Int String
 -- bar = proc x -> do
---     food <- sealState foo 5 -< x
---     id -< (food, show x)
+--     hey <- sealReader (effect ask) "hey" -< ()
+--     id -< hey ++ show x
 -- @
 --
--- >>> streamAuto' bar [1..10]
--- [ (7, "1"), (15, "2"), (19, "3"), (36, "4"), (42, "5"), (75, "6") ...
+-- >>> streamAuto' bar [1..5]
+-- ["hey1", "hey2", "hey3", "hey4", "hey5"]
 --
--- We say that @'sealState' f s0@ takes an input stream, and the output
--- stream is the result of running the stream through @f@, first with an
--- initial state of @s0@, and afterwards with each next updated state.
+-- Note that this version serializes the given @r@ environment, so that
+-- every time the 'Auto' is reloaded/resumed, it resumes with the
+-- originally given @r@ environment, ignoring whatever @r@ is given to it
+-- when trying to resume it.  If this is not the behavior you want, use
+-- 'sealReader_'.
 --
-sealState :: (Monad m, Serialize s)
-          => Auto (StateT s m) a b    -- ^ 'Auto' run over 'State'
-          -> s                        -- ^ initial state
-          -> Auto m a b
-sealState a s0 = mkAutoM (sealState <$> resumeAuto a <*> get)
-                         (saveAuto a *> put s0)
+-- 'Reader' is convenient because it allows you to "chain" and "compose"
+-- 'Auto's with a common environment, instead of explicitly passing in
+-- values every time.  For a convenient way of generating 'Auto's under
+-- 'ReaderT', and also for some motivating examples, see 'readerA' and
+-- 'runReaderA'.
+--
+sealReader :: (Monad m, Serialize r)
+           => Auto (ReaderT r m) a b    -- ^ 'Auto' run over 'Reader'
+           -> r                         -- ^ the perpetual environment
+           -> Auto m a b
+sealReader a r = mkAutoM (sealReader <$> resumeAuto a <*> get)
+                         (saveAuto a *> put r)
                        $ \x -> do
-                           ((y, a'), s1) <- runStateT (stepAuto a x) s0
-                           return (y, sealState a' s1)
+                           (y, a') <- runReaderT (stepAuto a x) r
+                           return (y, sealReader a' r)
 
--- | The non-resuming/non-serializing version of 'sealState'.
-sealState_ :: Monad m
-           => Auto (StateT s m) a b   -- ^ 'Auto' run over 'State'
-           -> s                       -- ^ initial state
-           -> Auto m a b
-sealState_ a s0 = mkAutoM (sealState_ <$> resumeAuto a <*> pure s0)
+-- | The non-resuming/non-serializing version of 'sealReader'.  Does not
+-- serialize/reload the @r@ environment, so that whenever you "resume" the
+-- 'Auto', it uses the new @r@ given when you are trying to resume, instead
+-- of loading the originally given one.
+sealReader_ :: Monad m
+            => Auto (ReaderT r m) a b   -- ^ 'Auto' run over 'Reader'
+            -> r                        -- ^ the perpetual environment
+            -> Auto m a b
+sealReader_ a r = mkAutoM (sealReader_ <$> resumeAuto a <*> pure r)
                           (saveAuto a)
-                          $ \x -> do
-                              ((y, a'), s1) <- runStateT (stepAuto a x) s0
-                              return (y, sealState_ a' s1)
+                        $ \x -> do
+                            (y, a') <- runReaderT (stepAuto a x) r
+                            return (y, sealReader_ a' r)
 
--- | Turns an @a -> 'StateT' s m b@ Kleisli arrow into an @'Auto' m a b@,
--- when given an initial state.  Will continually "run the function", using
--- the state returned from the last run.
-fromState :: (Serialize s, Monad m)
-          => (a -> StateT s m b)      -- ^ 'State' arrow
-          -> s                        -- ^ initial state
-          -> Auto m a b
-fromState st = mkStateM (runStateT . st)
+-- | Transforms an 'Auto' on two input streams ( a "normal input" stream
+-- @a@ and an "environment input stream" @r@) into an 'Auto' on one input
+-- stream @a@ with an underlying environment @r@ through a 'Reader' monad.
+--
+-- Why is this useful?  Well, if you have several 'Auto's that all take in
+-- a side @r@ stream, and you want to convey that every single one should
+-- get the /same/ @r@ at every step, you can instead have all of them pull
+-- from a common underlying global environment.
+--
+-- Note: Function is the inverse of 'runReaderA':
+--
+-- @
+-- 'readerA' . 'runReaderA' == 'id'
+-- 'runReaderA' . 'readerA' == 'id'
+-- @
+readerA :: Monad m
+        => Auto m (a, r) b           -- ^ 'Auto' receiving an environment.
+        -> Auto (ReaderT r m) a b    -- ^ 'Auto' run over an environment.
+readerA a = mkAutoM (readerA <$> resumeAuto a)
+                    (saveAuto a)
+                  $ \x -> ReaderT $ \r -> do
+                      (y, a') <- stepAuto a (x, r)
+                      return (y, readerA a')
 
--- | Non-seralizing/non-resuming version of 'fromState'.  The state isn't
--- serialized/resumed, so every time the 'Auto' is resumed, it starts over
--- with the given initial state.
-fromState_ :: Monad m
-           => (a -> StateT s m b)     -- ^ 'State' arrow
-           -> s                       -- ^ initial state
-           -> Auto m a b
-fromState_ st = mkStateM_ (runStateT . st)
+-- $writer
+-- 'WriterT' gives you a shared "sink" to dump data into.  You can dump in
+-- data by using
+--
+-- @
+-- 'arrM' 'tell' :: 'MonadWriter' w m => 'Auto' m w ()
+-- 'effect' . 'tell' :: 'MonadWriter' w m => w -> 'Auto' m a ()
+-- @
+--
+-- @
+-- foo :: Auto (Writer (Sum Int)) Int Int
+-- foo = effect (tell 1) *> effect (tell 1) *> sumFrom 0
+-- @
+--
+-- >>> let fooWriter = streamAuto foo
+-- >>> runWriter $ fooWriter [1..10]
+-- ([1,3,6,10,15,21,28,36,45,55], Sum 20)
+--
+-- @foo@ increments an underlying counter twice every time it is stepped;
+-- its "result" is just the cumulative sum of the inputs.
+--
+-- If you have several 'Auto's that all output some "side-channel" value
+-- that is just all accumulated at the end, and you want to implicitly
+-- accumulate it all, you can just have them all dump into an underlying
+-- 'Writer' sink instead of aggregating them explicitly.
+--
+-- For example:
+--
+-- @
+-- foo :: Auto m Int (Bool, [String])
+-- bar :: Auto m Bool (Int, [String])
+-- baz :: Auto m Bool (String, [String])
+-- @
+--
+-- Each of these has a "logging output" that should be aggregated all at
+-- the end.
+--
+-- One way you can do this is by using an explicit proc block:
+--
+-- @
+-- full :: Auto m Int (String, [String])
+-- full = proc inp -> do
+--     x <- sumFrom 0 -< inp
+--     (fo, foW) <- foo -< inp + x
+--     (br, brW) <- bar -< fo
+--     (bz, bzW) <- baz -< fo
+--     id -< (replicate br bz, foW <> brW <> bzW)
+-- @
+--
+-- Or, you can handle the extra output implicitly using 'writerA':
+--
+-- @
+-- fullW :: Auto (WriterT [String] m) Int String
+-- fullW = proc inp -> do
+--     x  <- sumFrom 0   -< inp
+--     fo <- writerA foo -< inp + x
+--     br <- writerA bar -< fo
+--     bz <- writerA baz -< fo
+--     id -< replicate br bz
+-- @
+--
+-- Note that @'sumFrom' 0@ still works the same and doesn't interfere,
+-- logging nothing.
+--
+-- You can recover the original @full@ with 'runWriterA', which
+-- "unwraps" the underlying 'Writer':
+--
+-- @
+-- full' :: Auto m Int (String, [String])
+-- full' = runWriterA fullW
+-- @
+--
 
 -- | "Unrolls" the underlying @'WriterT' w m@ 'Monad', so that an 'Auto'
 -- that takes in a stream of @a@ and outputs a stream of @b@ will now
 -- output a stream @(b, w)@, where @w@ is the "new log" of the underlying
 -- 'Writer' at every step.
 --
+-- Examples:
+--
 -- @
 -- foo :: Auto (Writer (Sum Int)) Int Int
 -- foo = effect (tell 1) *> effect (tell 1) *> sumFrom 0
@@ -351,6 +541,8 @@
 -- access.  There, @w@ represents the continually updating accumulator
 -- under @foo@, and will be different/growing at every "step".
 --
+-- For a convenient way to /create/ an 'Auto' under 'WriterT', see
+-- 'writerA'.
 runWriterA :: (Monad m, Monoid w)
            => Auto (WriterT w m) a b
            -> Auto m a (b, w)
@@ -360,58 +552,146 @@
                          ((y, a'), w) <- runWriterT (stepAuto a x)
                          return ((y, w), runWriterA a')
 
--- | Takes an 'Auto' that operates under the context of a read-only
--- environment, an environment value, and turns it into a normal 'Auto'
--- that always "sees" that value when it asks for one.
+
+-- | Transforms an 'Auto' on with two output streams (a "normal output
+-- stream" @b@, and a "logging output stream" @w@) into an 'Auto' with just
+-- one output stream @a@, funneling the logging stream @w@ into an
+-- underlying 'WriterT' monad.
 --
--- >>> let a   = effect ask :: Auto (Reader b) a b
--- >>> let rdr = streamAuto' a [1..5] :: Reader b [b]
--- >>> runReader rdr "hey"
--- ["hey", "hey", "hey", "hey", "hey"]
+-- Note: Function is the inverse of 'runWriterA':
 --
--- Useful if you wanted to use it inside/composed with an 'Auto' that does
--- not have a global environment:
+-- @
+-- 'writerA' . 'runWriterA' == 'id'
+-- 'runWriterA' . 'writerA' == 'id'
+-- @
+writerA :: (Monad m, Monoid w)
+        => Auto m a (b, w)          -- ^ 'Auto' with a "normal" output
+                                    --     stream @b@s and a "logging"
+                                    --     stream @w@s
+        -> Auto (WriterT w m) a b   -- ^ 'Auto' under an underlying
+                                    --     'WriterT', logging @w@s
+writerA a = mkAutoM (writerA <$> resumeAuto a)
+                    (saveAuto a)
+                  $ \x -> WriterT $ do
+                      ((y, w), a') <- stepAuto a x
+                      return ((y, writerA a'), w)
+
+-- $state
+-- An underlying 'StateT' gives you access to a global, mutable state.
 --
+-- At first this might be seem a little silly.  We went through all this
+-- trouble to avoid the headache of global mutable state, and now we add ti
+-- back in?
+--
+-- One nice usage is an underlying entropy generator (you can deal with
+-- this more explicitly with 'sealRandom' in
+-- "Control.Auto.Process.Random"), or maybe some underlying pool that every
+-- 'Auto' shares that would be a big headache to thread manually.
+--
+-- The main benefit here is that, using tools like 'sealState' and
+-- 'runStateA', we can /isolate/ the portion of our program that takes
+-- advantage of shared mutable state, and /seal off/ or only give that part
+-- access to the state... and nobody else.
+--
+-- Anyways, it should go without saying that you should think really long
+-- and really hard before adding in global state to your program.  It is
+-- almost always better to use principles of local statefulness and
+-- denotative composition to achieve what you want.  Relying on this
+-- construct might lead to very unmaintainable code, and definitely code
+-- that is much more difficult to reason with.  I suggest trying to find
+-- another solution first in all cases!
+
+-- | Takes an 'Auto' that works with underlying global, mutable state, and
+-- "seals off the state" from the outside world.
+--
+-- An 'Auto (StateT s m) a b' maps a stream of 'a' to a stream of 'b', but
+-- does so in the context of requiring an initial 's' to start, and
+-- outputting a modified 's'.
+--
+-- Consider this example 'State' 'Auto':
+--
 -- @
--- bar :: Auto' Int String
+-- foo :: Auto (State s) Int Int
+-- foo = proc x -> do
+--     execB (modify (+1)) . emitOn odd  -< x
+--     execB (modify (*2)) . emitOn even -< x
+--     st   <- effect get -< ()
+--     sumX <- sumFrom 0  -< x
+--     id    -< sumX + st
+-- @
+--
+-- On every output, the "global" state is incremented if the input is odd
+-- and doubled if the input is even.  The stream @st@ is always the value
+-- of the global state at that point.  @sumX@ is the cumulative sum of the
+-- inputs.  The final result is the sum of the value of the global state
+-- and the cumulative sum.
+--
+-- In writing like this, you lose some of the denotative properties because
+-- you are working with a global state that updates at every output.  You
+-- have some benefit of now being able to work with global state, if that's
+-- what you wanted I guess.
+--
+-- To "run" it, you could use 'streamAuto' to get a @'State' Int Int@:
+--
+-- >>> let st = streamAuto foo [1..10] :: State Int Int
+-- >>> runState st 5
+-- ([  7, 15, 19, 36, 42, 75, 83,136,156,277], 222)
+--
+-- (The starting state is 5 and the ending state after all of that is 222)
+--
+-- However, writing your entire program with global state is a bad bad
+-- idea!  So, how can you get the "benefits" of having small parts like
+-- @foo@ be written using 'State', and being able to use it in a program
+-- with no global state?
+--
+-- Using 'sealState'!  Write the part of your program that would like
+-- shared global state with 'State'...and compose it with the rest as if it
+-- doesn't, locking it away!
+--
+-- @
+-- sealState       :: Auto (State s) a b -> s -> Auto' a b
+-- sealState foo 5 :: Auto' Int Int
+-- @
+--
+-- @
+-- bar :: Auto' Int (Int, String)
 -- bar = proc x -> do
---     hey <- sealReader (effect ask) "hey" -< ()
---     id -< hey ++ show x
+--     food <- sealState foo 5 -< x
+--     id -< (food, show x)
 -- @
 --
--- >>> streamAuto' bar [1..5]
--- ["hey1", "hey2", "hey3", "hey4", "hey5"]
+-- >>> streamAuto' bar [1..10]
+-- [ (7, "1"), (15, "2"), (19, "3"), (36, "4"), (42, "5"), (75, "6") ...
 --
--- Note that this version serializes the given @r@ environment, so that
--- every time the 'Auto' is reloaded/resumed, it resumes with the
--- originally given @r@ environment, ignoring whatever @r@ is given to it
--- when trying to resume it.  If this is not the behavior you want, use
--- 'sealReader_'.
+-- We say that @'sealState' f s0@ takes an input stream, and the output
+-- stream is the result of running the stream through @f@, first with an
+-- initial state of @s0@, and afterwards with each next updated state.
 --
-sealReader :: (Monad m, Serialize r)
-           => Auto (ReaderT r m) a b    -- ^ 'Auto' run over 'Reader'
-           -> r                         -- ^ the perpetual environment
-           -> Auto m a b
-sealReader a r = mkAutoM (sealReader <$> resumeAuto a <*> get)
-                         (saveAuto a *> put r)
+-- For a convenient way of "creating" an 'Auto' under 'StateT' in the first
+-- place, see 'stateA'.
+--
+sealState :: (Monad m, Serialize s)
+          => Auto (StateT s m) a b    -- ^ 'Auto' run over 'State'
+          -> s                        -- ^ initial state
+          -> Auto m a b
+sealState a s0 = mkAutoM (sealState <$> resumeAuto a <*> get)
+                         (saveAuto a *> put s0)
                        $ \x -> do
-                           (y, a') <- runReaderT (stepAuto a x) r
-                           return (y, sealReader a' r)
+                           ((y, a'), s1) <- runStateT (stepAuto a x) s0
+                           return (y, sealState a' s1)
 
--- | The non-resuming/non-serializing version of 'sealReader'.  Does not
--- serialize/reload the @r@ environment, so that whenever you "resume" the
--- 'Auto', it uses the new @r@ given when you are trying to resume, instead
--- of loading the originally given one.
-sealReader_ :: Monad m
-            => Auto (ReaderT r m) a b   -- ^ 'Auto' run over 'Reader'
-            -> r                        -- ^ the perpetual environment
-            -> Auto m a b
-sealReader_ a r = mkAutoM (sealReader_ <$> resumeAuto a <*> pure r)
+-- | The non-resuming/non-serializing version of 'sealState'.
+sealState_ :: Monad m
+           => Auto (StateT s m) a b   -- ^ 'Auto' run over 'State'
+           -> s                       -- ^ initial state
+           -> Auto m a b
+sealState_ a s0 = mkAutoM (sealState_ <$> resumeAuto a <*> pure s0)
                           (saveAuto a)
-                        $ \x -> do
-                            (y, a') <- runReaderT (stepAuto a x) r
-                            return (y, sealReader_ a' r)
+                          $ \x -> do
+                              ((y, a'), s1) <- runStateT (stepAuto a x) s0
+                              return (y, sealState_ a' s1)
 
+
 -- | "Unrolls" the underlying 'StateT' of an 'Auto' into an 'Auto' that
 -- takes in an input state every turn (in addition to the normal input) and
 -- outputs, along with the original result, the modified state.
@@ -425,37 +705,112 @@
 --
 -- When used with @'State' s@, it turns an @'Auto' ('State' s) a b@ into an
 -- @'Auto'' (a, s) (b, s)@.
+--
+-- For a convenient way to "generate" an 'Auto' 'StateT', see 'stateA'
+--
 runStateA :: Monad m
           => Auto (StateT s m) a b      -- ^ 'Auto' run over a state transformer
-          -> Auto m (a, s) (b, s)       -- ^ 'Auto' whose inputs and outputs are a start transformer
+          -> Auto m (a, s) (b, s)       -- ^ 'Auto' whose inputs and outputs are a state transformer
 runStateA a = mkAutoM (runStateA <$> resumeAuto a)
                       (saveAuto a)
                     $ \(x, s) -> do
                         ((y, a'), s') <- runStateT (stepAuto a x) s
                         return ((y, s'), runStateA a')
 
--- | "Unrolls" the underlying 'ReaderT' of an 'Auto' into an 'Auto' that
--- takes in the input "environment" every turn in addition to the normal
--- input.
+
+-- | Transforms an 'Auto' with two input streams and two output streams (a
+-- "normal" input @a@ output @b@ stream, and a "state transforming"
+-- side-stream taking in @s@ and outputting @s@), abstracts away the @s@
+-- stream as a modifcation to an underyling 'StateT' monad.  That is, your
+-- normal inputs and outputs are now your /only/ inputs and outputs, and
+-- your input @s@ comes from the underlying global mutable state, and the
+-- output @s@ goes to update the underlying global mutable state.
 --
--- So you can use any @'ReaderT' r m@ as if it were an @m@.  Useful if you
--- want to compose and create some isolated 'Auto's with access to an
--- underlying environment, but not your entire program.
+-- For example, you might have a bunch of 'Auto's that interact with
+-- a global mutable state:
 --
--- Also just simply useful as a convenient way to use an 'Auto' over
--- 'Reader' with 'stepAuto' and friends.
+-- @
+-- foo :: Auto (StateT Double m) Int Bool
+-- bar :: Auto (StateT Double m) Bool Int
+-- baz :: Auto (StateT Double m) Bool String
+-- @
 --
--- When used with @'Reader' r@, it turns an @'Auto' ('Reader' r) a b@ into
--- an @'Auto'' (a, r) b@.
-runReaderA :: Monad m
-           => Auto (ReaderT r m) a b    -- ^ 'Auto' run over global environment
-           -> Auto m (a, r) b           -- ^ 'Auto' receiving environments
-runReaderA a = mkAutoM (runReaderA <$> resumeAuto a)
-                       (saveAuto a)
-                     $ \(x, r) -> do
-                         (y, a') <- runReaderT (stepAuto a x) r
-                         return (y, runReaderA a')
+-- Where @foo@, @bar@, and @baz@ all interact with global mutable state.
+-- You'd use them like this:
+--
+-- @
+-- full :: Auto (StateT Double m) Int String
+-- full = proc inp -> do
+--     fo <- foo -< inp
+--     br <- bar -< fo
+--     bz <- baz -< fo
+--     id -< replicae br bz
+-- @
+--
+-- 'stateA' allows you generate a new @Auto@ under 'StateT':
+--
+-- @
+-- thing :: Auto m (Int, Double) (Bool, Double)
+-- stateA thing :: Auto (StateT Double m) Int Bool
+-- @
+--
+-- So now the two side-channels are interpreted as working with the global
+-- state:
+--
+-- @
+-- full :: Auto (StateT Double m) Int String
+-- full = proc inp -> do
+--     fo <- foo          -< inp
+--     tg <- stateA thing -< inp
+--     br <- bar          -< fo || tg
+--     bz <- baz          -< fo && tg
+--     id -< replicae br bz
+-- @
+--
+-- You can then "seal it all up" in the end with an initial state, that
+-- keeps on re-running itself with the resulting state every time:
+--
+-- @
+-- full' :: Double -> Auto m Int String
+-- full' = sealState full
+-- @
+--
+-- Admittedly, this is a bit more esoteric and dangerous (programming with
+-- global state? what?) than its components 'readerA' and 'writerA';
+-- I don't actually recommend you programming with global state unless it
+-- really is the best solution to your problem...it tends to encourage
+-- imperative code/loops, and "unreasonable" and manageable code.  See
+-- documentation for 'sealStateA' for best practices.  Basically every bad
+-- thing that comes with global mutable state.  But, this is provided here
+-- for sake of completeness with 'readerA' and 'writerA'.
+--
+-- Note: function is the inverse of 'runstateA'.
+--
+-- @
+-- 'stateA' . 'runStateA' == 'id'
+-- 'runStateA' . 'stateA' == 'id'
+-- @
+stateA :: Monad m
+       => Auto m (a, s) (b, s)   -- ^ 'Auto' whose inputs and outputs are a
+                                 --     state transformer
+       -> Auto (StateT s m) a b  -- ^ 'Auto' run over a state transformer
+stateA a = mkAutoM (stateA <$> resumeAuto a)
+                   (saveAuto a)
+                 $ \x -> StateT $ \s -> do
+                     ((y, s'), a') <- stepAuto a (x, s)
+                     return ((y, stateA a'), s')
 
+-- | Like 'stateA', but assumes that the output is the modified state.
+accumA :: Monad m
+       => Auto m (a, s) s   -- ^ 'Auto' taking inputs and states and
+                            --     returning updated states
+       -> Auto (StateT s m) a s     -- ^ 'Auto' over a state transformer
+accumA a = mkAutoM (accumA <$> resumeAuto a)
+                   (saveAuto a)
+                 $ \x -> StateT $ \s -> do
+                     (s', a') <- stepAuto a (x, s)
+                     return ((s', accumA a'), s')
+
 -- | "Unrolls" the underlying 'Monad' of an 'Auto' if it happens to be
 -- 'Traversable' ('[]', 'Maybe', etc.).
 --
@@ -463,13 +818,32 @@
 -- collects all of the results together.  Or an @'Auto' 'Maybe' a b@ into
 -- an @'Auto'' a ('Maybe' b)@.
 --
--- This might be useful if you want to make some sort of "underyling
+-- This might be useful if you want to make some sort of "underlying
 -- inhibiting" 'Auto' where the entire computation might just end up being
 -- 'Nothing' in the end.  With this, you can turn that
 -- possibly-catastrophically-failing 'Auto' (with an underlying 'Monad' of
 -- 'Maybe') into a normal 'Auto', and use it as a normal 'Auto' in
 -- composition with other 'Auto's...returning 'Just' if your computation
 -- succeeded.
+--
+-- @
+-- 'runTraversableA' :: 'Auto' 'Maybe' a b -> 'Interval'' a b
+-- @
+--
+-- @
+-- foo :: Auto Maybe Int Int
+-- foo = arrM $ \x -> if even x then Just (x `div` 2) else Nothing
+--
+-- bar :: Auto Maybe Int Int
+-- bar = arrM Just
+-- @
+--
+-- >>> streamAuto (foo &&& bar) [2,4,6]
+-- Just [(1, 2),(2, 4),(3, 6)]
+-- >>> streamAuto (foo &&& bar) [2,4,6,7]
+-- Nothing
+-- >>> streamAuto' ('runTraversableA' foo '<|?>' 'runTraversableA' bar) [2,4,6,7]
+-- [Just 1, Just 2, Just 3, Just 7]
 runTraversableA :: (Monad f, Traversable f)
                 => Auto f a b           -- ^ 'Auto' run over traversable structure
                 -> Auto m a (f b)       -- ^ 'Auto' returning traversable structure
@@ -488,10 +862,6 @@
 --
 -- Note that you have to explicitly specify the type of the exceptions you
 -- are catching; see "Control.Exception" documentation for more details.
---
--- TODO: Possibly look into bringing in some more robust tools from
--- monad-control and other industry established error handling routes?
--- Also, can we modify an underlying monad with implicit cacting behavior?
 catchA :: Exception e
        => Auto IO a b               -- ^ Auto over IO, expecting an
                                     --     exception of a secific type.
@@ -505,3 +875,6 @@
                    case eya' of
                      Right (y, a') -> return (Right y, catchA a')
                      Left e        -> return (Left e , a_)
+-- TODO: Possibly look into bringing in some more robust tools from
+-- monad-control and other industry established error handling routes?
+-- Also, can we modify an underlying monad with implicit catching behavior?
diff --git a/src/Control/Auto/Process/Random.hs b/src/Control/Auto/Process/Random.hs
--- a/src/Control/Auto/Process/Random.hs
+++ b/src/Control/Auto/Process/Random.hs
@@ -132,7 +132,6 @@
 import Control.Category
 import Control.Monad              (guard)
 import Control.Monad.Random
-import Control.Monad.Trans.State  (StateT(..))
 import Data.Bits
 import Data.Serialize
 import Data.Tuple
@@ -495,7 +494,11 @@
            => Auto (RandT g m) a b        -- ^ 'Auto' to seal
            -> g                           -- ^ initial seed
            -> Auto m a b
-sealRandom a = sealState (hoistA (StateT . runRandT) a)
+sealRandom a g0 = mkAutoM (sealRandom <$> resumeAuto a <*> get)
+                          (saveAuto a *> put g0)
+                        $ \x -> do
+                            ((y, a'), g1) <- runRandT (stepAuto a x) g0
+                            return (y, sealRandom a' g1)
 
 -- | The non-serializing/non-resuming version of 'sealRandom_'.  The random
 -- seed is not re-loaded/resumed, so every time you resume, the stream of
@@ -504,7 +507,11 @@
             => Auto (RandT g m) a b         -- ^ 'Auto' to seal
             -> g                            -- ^ initial seed
             -> Auto m a b
-sealRandom_ a = sealState_ (hoistA (StateT . runRandT) a)
+sealRandom_ a g0 = mkAutoM (sealRandom_ <$> resumeAuto a <*> pure g0)
+                           (saveAuto a)
+                         $ \x -> do
+                             ((y, a'), g1) <- runRandT (stepAuto a x) g0
+                             return (y, sealRandom_ a' g1)
 
 -- | Like 'sealRandom', but specialized for 'StdGen' from "System.Random",
 -- so that you can serialize and resume.  This is needed because 'StdGen'
diff --git a/tutorial/tutorial.md b/tutorial/tutorial.md
--- a/tutorial/tutorial.md
+++ b/tutorial/tutorial.md
@@ -402,6 +402,10 @@
 This reads as you are defining a binding `prodX`, and `prodX` is maintained as
 the cumulative product of `x + sumX`.
 
+All "values" in your proc block are actually *streams*.  `prodX` is a stream
+of numbers, `x` is a stream, `sumX` is a stream...and `productFrom 1` lets you
+describe the (static) *relationship* between those three streams.
+
 The result of the last line of the proc block is the result of the entire
 block:
 
@@ -409,8 +413,8 @@
 id -< (prodX, lastEven)
 ~~~
 
-Means that the output of the entire block is just echoing the tuple `(prodX,
-lastEven)`.
+Means that the output stream of the entire block is just echoing the tuple
+`(prodX, lastEven)`.
 
 (Operationally, you can imagine that, at every step, `x` is "fed into"
 `sumFrom 0`, and the result is named `sumX`; `x + sumX` is "fed into"
@@ -441,13 +445,13 @@
     id -< y + z
 ~~~
 
-We can't do `sumFrom y`, because `y` is not an actual value that we have at
-"compile"/"building" time.  `y` is what we're calling the result of
-`productFrom 1`, at every step, so its value changes at every step, and every
-`Auto` has to be a **fixed `Auto`**.  Remember, `Auto` relationships are
-"forever" and fixed, declarative style.  So the `Auto` where `sumFrom` is,
-there, has to be a fixed thing that doesn't change at every step...but `y` is
-a value that will very as the stream marches on.
+We can't do `sumFrom y`, because `y` isn't actually a "value" we have at
+"compile"/"building" time...`y` is the stream that is the cumulative product
+of the stream `x`.  `y` changes at every "point in time".  Remember, `Auto`
+relationships in a proc block are "fixed", and "forever"; `productFrom 1` is
+the "static relationship" between `x` and `y`.  So the `Auto` where `sumFrom`
+is...it has to be a fixed thing that never changes.  But `y` changes every
+step!
 
 You can however do something like:
 
