diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@
 \^ That guide will bring you through the process of making your first app!
 
 If you have any issues (and I'm sure there'll be a few; it's a new project!)
-please report them [here](https://github.com/ChrisPenner/rasa/issues).
+please report them [here](https://github.com/ChrisPenner/eve/issues).
 
 Core Principles
 ---------------
diff --git a/eve.cabal b/eve.cabal
--- a/eve.cabal
+++ b/eve.cabal
@@ -1,5 +1,5 @@
 name:                eve
-version:             0.1.0
+version:             0.1.1
 synopsis: An extensible event framework
 description: An extensible event-driven application framework in haskell for building embarassingly modular software.
 homepage:            https://github.com/ChrisPenner/eve#readme
@@ -16,11 +16,12 @@
 library
   hs-source-dirs:      src
   exposed-modules:     Eve
-                     , Eve.Internal.Testing
+                     , Eve.Testing
                      , Eve.Internal.Actions
+                     , Eve.Internal.AppState
                      , Eve.Internal.Async
                      , Eve.Internal.Events
-                     , Eve.Internal.Extensions
+                     , Eve.Internal.States
                      , Eve.Internal.Listeners
                      , Eve.Internal.Run
   build-depends:       base >= 4.7 && < 5
diff --git a/src/Eve.hs b/src/Eve.hs
--- a/src/Eve.hs
+++ b/src/Eve.hs
@@ -1,10 +1,15 @@
 module Eve
   ( eve
+  , eveT
 
   , App
   , Action
+  , AppT
+  , ActionT
   , liftAction
+  , AppState
 
+  -- * Events
   , dispatchEvent
   , dispatchEvent_
   , dispatchEventAsync
@@ -14,6 +19,15 @@
   , addListener_
   , removeListener
 
+  -- * Working with Async Events/Actions
+  , asyncActionProvider
+  , asyncEventProvider
+  , Dispatcher
+
+  , Listener
+  , ListenerId
+
+  -- * Built-in Event Listeners
   , onInit
   , afterInit
   , beforeEvent
@@ -22,16 +36,49 @@
   , afterEvent_
   , onExit
 
-  , asyncActionProvider
-  , asyncEventProvider
-
-  , Listener
-  , ListenerId
-
-  , HasExts(..)
-  , Exts
+  -- * Working with State
+  -- | All application-provided states are stored in the same
+  -- Map; keyed by their 'Data.Typeable.TypeRep'. This means that if more than one state
+  -- uses the same type then they'll conflict and overwrite each-other (this is less of a
+  -- problem than you're probably thinking). This is easily solved by simply
+  -- using a newtype around any types you haven't defined yourself.
+  -- For example if your application stores a counter as an Int, wrap it in your own custom
+  -- @Counter@ newtype when storing it. If you wish to store multiple copies of a given state
+  -- simply store them in a list or map, then store that container as your state.
+  --
+  -- Because states are stored by their 'Data.Typeable.TypeRep', they must define an
+  -- instance of 'Data.Typeable.Typeable', luckily GHC can derive this for you with
+  -- @deriving Typeable@.
+  --
+  -- It is also required for all states to define an instance of
+  -- 'Data.Default.Default', this is because accessing an extension which has not
+  -- yet been stored will result in the default value.
+  --
+  -- If there's no default value that makes sense for your type, you can define
+  -- a default of 'Data.Maybe.Nothing' and pattern-match on its value when you
+  -- access it.
+  --
+  -- Stored states are accessed by using the `stateLens` lens, this lens is polymorphic
+  -- and can return ANY type. GHC infers the needed type and the lens will retrieve the
+  -- state that you want from the store of states. It seems a bit complicated, but it all
+  -- works fine in practice.
+  --
+  -- To avoid confusion it's best to rename a version of `stateLens` with a more restrictive
+  -- type for each different state type that you store. This helps prevent strange errors and
+  -- makes your code much easier to read. For example:
+  --
+  -- > data MyState = MyState String
+  -- > myState :: HasStates s => Lens' s MyState
+  -- > myState = stateLens
+  -- >
+  -- > myAction = do
+  -- >   MyState str <- use stateLens
+  --
+  -- If GHC has trouble inferring the type, rename it and restrict the type as above.
+  , HasStates(..)
+  , States
   , HasEvents
-  , ext
+  , stateLens
 
   , runAction
   , exit
@@ -41,4 +88,5 @@
 import Eve.Internal.Actions
 import Eve.Internal.Listeners
 import Eve.Internal.Async
-import Eve.Internal.Extensions
+import Eve.Internal.AppState
+import Eve.Internal.States
diff --git a/src/Eve/Internal/Actions.hs b/src/Eve/Internal/Actions.hs
--- a/src/Eve/Internal/Actions.hs
+++ b/src/Eve/Internal/Actions.hs
@@ -2,74 +2,77 @@
 {-# language DeriveFunctor #-}
 {-# language FlexibleInstances #-}
 {-# language MultiParamTypeClasses #-}
-{-# language TemplateHaskell #-}
 {-# language RankNTypes #-}
 {-# language TypeFamilies #-}
 {-# language UndecidableInstances #-}
 {-# language ScopedTypeVariables #-}
+{-# language TemplateHaskell #-}
 module Eve.Internal.Actions
-  ( Action(..)
-  , ActionF(..)
-  , App
+  ( ActionF(..)
+  , ActionT(..)
+  , AppT
+  , runApp
+  , evalApp
   , execApp
 
-  , AppState(..)
-  , asyncQueue
-
   , liftAction
   , runAction
 
   , exit
   , isExiting
+  , asyncQueue
   , Exiting(..)
   ) where
 
-import Eve.Internal.Extensions
-import Data.Default
+import Eve.Internal.States
 
 import Control.Monad.State
 import Control.Monad.Trans.Free
 import Control.Lens
+import Data.Default
+import Data.Typeable
 
 import Pipes.Concurrent
 
-type App a = Action AppState a
-data AppState = AppState
-  { _baseExts :: Exts
-  , _asyncQueue :: Output (App ())
-  }
+type AppT s m a = ActionT s s m a
 
-newtype ActionF next =
-  LiftAction (StateT AppState IO next)
+newtype ActionF base m next =
+  LiftAction (StateT base m next)
   deriving (Functor, Applicative)
 
-newtype Action zoomed a = Action
-  { getAction :: FreeT ActionF (StateT zoomed IO) a
-  } deriving (Functor, Applicative, Monad, MonadIO, MonadState zoomed, MonadFree ActionF)
-makeLenses ''AppState
+newtype ActionT base zoomed m a = ActionT
+  { getAction :: FreeT (ActionF base m) (StateT zoomed m) a
+  } deriving (Functor, Applicative, Monad, MonadIO, MonadState zoomed)
 
-instance HasExts AppState where
-  exts = baseExts
+instance Monad n => MonadFree (ActionF base n) (ActionT base zoomed n) where
+  wrap (LiftAction act) = join . ActionT . liftF . LiftAction $ act
 
-instance HasEvents AppState where
+instance MonadTrans (ActionT base zoomed) where
+  lift = ActionT . lift . lift
 
-unLift :: FreeT ActionF (StateT AppState IO) a -> StateT AppState IO a
+unLift :: Monad m => FreeT (ActionF base m) (StateT base m) a -> StateT base m a
 unLift m = do
   step <- runFreeT m
   case step of
     Pure a -> return a
     Free (LiftAction next) -> next >>= unLift
 
-liftAction :: Action AppState a -> Action zoomed a
+liftAction :: Monad m => AppT base m a -> ActionT base zoomed m a
 liftAction = liftF .  LiftAction . unLift . getAction
 
-execApp :: AppState -> Action AppState a -> IO a
-execApp appState = flip evalStateT appState . unLift . getAction
+runApp :: Monad m => base -> AppT base m a -> m (a, base)
+runApp baseState = flip runStateT baseState . unLift . getAction
 
-type instance Zoomed (Action s) = Zoomed (FreeT ActionF (StateT s IO))
-instance Zoom (Action s) (Action t) s t where
-  zoom l (Action action) = Action $ zoom l action
+evalApp :: Monad m => base -> AppT base m a -> m a
+evalApp baseState = fmap fst . runApp baseState
 
+execApp :: Monad m => base -> AppT base m a -> m base
+execApp baseState = fmap snd . runApp baseState
+
+type instance Zoomed (ActionT base zoomed m) = Zoomed (FreeT (ActionF base m) (StateT zoomed m))
+instance Monad m => Zoom (ActionT base s m) (ActionT base t m) s t where
+  zoom l (ActionT action) = ActionT $ zoom l action
+
 runAction :: Zoom m n s t => LensLike' (Zoomed m c) t s -> m c -> n c
 runAction = zoom
 
@@ -80,10 +83,24 @@
 instance Default Exiting where
   def = Exiting False
 
-exit :: App ()
-exit = ext .= Exiting True
+exit :: (Monad m, HasStates s) => ActionT s zoomed m ()
+exit = liftAction $ stateLens .= Exiting True
 
-isExiting :: App Bool
-isExiting = do
-  Exiting b <- use ext
+isExiting :: (Monad m, HasStates s) => ActionT s zoomed m Bool
+isExiting = liftAction $ do
+  Exiting b <- use stateLens
   return b
+
+newtype AsyncQueue base m = AsyncQueue
+  { _asyncQueue' :: Maybe (Output (AppT base m ()))
+  } deriving Typeable
+makeLenses ''AsyncQueue
+
+instance Show (AsyncQueue base m) where
+  show _ = "Async Queue"
+
+instance Default (AsyncQueue base m) where
+  def = AsyncQueue Nothing
+
+asyncQueue :: (HasStates s, Typeable m, Typeable base) => Lens' s (Maybe (Output (AppT base m ())))
+asyncQueue = stateLens.asyncQueue'
diff --git a/src/Eve/Internal/AppState.hs b/src/Eve/Internal/AppState.hs
new file mode 100644
--- /dev/null
+++ b/src/Eve/Internal/AppState.hs
@@ -0,0 +1,27 @@
+{-# language TemplateHaskell #-}
+module Eve.Internal.AppState
+  ( AppState(..)
+  , App
+  , Action
+  ) where
+
+import Eve.Internal.Actions
+import Eve.Internal.States
+import Control.Lens
+import Data.Default
+
+data AppState = AppState
+  { _baseStates :: States
+  }
+makeLenses ''AppState
+
+instance Default AppState where
+  def = AppState mempty
+
+instance HasStates AppState where
+  states = baseStates
+
+instance HasEvents AppState where
+
+type App a = AppT AppState IO a
+type Action s a = ActionT AppState s IO a
diff --git a/src/Eve/Internal/Async.hs b/src/Eve/Internal/Async.hs
--- a/src/Eve/Internal/Async.hs
+++ b/src/Eve/Internal/Async.hs
@@ -9,25 +9,33 @@
   ) where
 
 import Eve.Internal.Actions
+import Eve.Internal.States
 
 import Control.Monad
 import Control.Monad.State
 import Control.Lens
+import Data.Typeable
 
 import Pipes
 import Pipes.Concurrent
 
 dispatchActionAsync
-  :: IO (App ()) -> App ()
-dispatchActionAsync asyncAction = do
-  queue <- use asyncQueue
-  let effect = (liftIO asyncAction >>= yield) >-> toOutput queue
-  liftIO . void . forkIO $ runEffect effect >> performGC
+  :: (MonadIO m, HasStates base, Typeable m, Typeable base) => IO (AppT base m ()) -> ActionT base zoomed m ()
+dispatchActionAsync asyncAction = liftAction $ do
+  mQueue <- use asyncQueue
+  case mQueue of
+    Nothing -> return ()
+    Just queue -> do
+      let effect = (liftIO asyncAction >>= yield) >-> toOutput queue
+      liftIO . void . forkIO $ runEffect effect >> performGC
 
-asyncActionProvider :: ((App () -> IO ()) -> IO ()) -> App ()
-asyncActionProvider provider = do
-  queue <- use asyncQueue
-  let dispatcher action =
-        let effect = yield action >-> toOutput queue
-        in void . forkIO $ runEffect effect >> performGC
-  liftIO . void . forkIO $ provider dispatcher
+asyncActionProvider :: (MonadIO m, HasStates base, Typeable m, Typeable base) => ((AppT base m () -> IO ()) -> IO ()) -> ActionT base zoomed m ()
+asyncActionProvider provider = liftAction $ do
+  mQueue <- use asyncQueue
+  case mQueue of
+    Nothing -> return ()
+    Just queue -> do
+      let dispatcher action =
+            let effect = yield action >-> toOutput queue
+            in void . forkIO $ runEffect effect >> performGC
+      liftIO . void . forkIO $ provider dispatcher
diff --git a/src/Eve/Internal/Extensions.hs b/src/Eve/Internal/Extensions.hs
deleted file mode 100644
--- a/src/Eve/Internal/Extensions.hs
+++ /dev/null
@@ -1,57 +0,0 @@
-{-# LANGUAGE ExistentialQuantification #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-
-module Eve.Internal.Extensions
-  ( Exts
-  , HasExts(..)
-  , HasEvents
-  , ext
-  ) where
-
-import Control.Lens
-import Data.Map
-import Unsafe.Coerce
-import Data.Maybe
-import Data.Typeable
-import Data.Default
-
--- | A wrapper to allow storing differing extensions in the same place.
-data Ext =
-  forall ext. (Typeable ext, Show ext) =>
-              Ext ext
-
-instance Show Ext where
-  show (Ext a) = show a
-
--- | A map of extension types to their current value.
-type Exts = Map TypeRep Ext
-
--- | Represents a state which can be extended.
--- 'exts' is a 'Lens'' which points to the state's 'Exts'
-class HasExts s  where
-  exts :: Lens' s Exts
-
--- | A typeclass to ensure people don't dispatch events to states which shouldn't
---   accept them.
---
--- To allow dispatching events in an action over your state simply define the
--- empty instance:
---
--- > instance HasEvents MyState where
--- -- Don't need anything here.
-class (Typeable s, HasExts s) =>
-      HasEvents s
-
--- | A polymorphic lens which accesses extensions in the extension state.
--- It returns the default value ('def') if a state has not yet been set.
-ext
-  :: forall a e.
-    (Show a, Typeable a, Default a, HasExts e)
-  => Lens' e a
-ext = lens getter setter
-  where
-    getter s =
-      fromMaybe def $ s ^. exts . at (typeRep (Proxy :: Proxy a)) . mapping coerce
-    setter s new =
-      set (exts . at (typeRep (Proxy :: Proxy a)) . mapping coerce) (Just new) s
-    coerce = iso (\(Ext x) -> unsafeCoerce x) Ext
diff --git a/src/Eve/Internal/Listeners.hs b/src/Eve/Internal/Listeners.hs
--- a/src/Eve/Internal/Listeners.hs
+++ b/src/Eve/Internal/Listeners.hs
@@ -24,9 +24,10 @@
 
   , Listener
   , ListenerId
+  , Dispatcher
   ) where
 
-import Eve.Internal.Extensions
+import Eve.Internal.States
 import Eve.Internal.Async
 import Eve.Internal.Actions
 import Eve.Internal.Events
@@ -46,28 +47,28 @@
 -- Though arbitrary actions may be performed in the configuration block;
 -- it's recommended to embed such actions in the onInit event listener
 -- so that all event listeners are registered before any dispatches occur.
-onInit :: App result -> App ()
-onInit action = void $ addListener (const (void action) :: Init -> App ())
+onInit :: forall base zoomed m result. (Monad m, HasEvents zoomed, Typeable m, Typeable base) => ActionT base zoomed m result -> ActionT base zoomed m ()
+onInit action = void $ addListener (const (void action) :: Init -> ActionT base zoomed m ())
 
-afterInit :: App a -> App ()
-afterInit action = void $ addListener (const (void action) :: AfterInit -> App ())
+afterInit :: forall base zoomed m a. (Monad m, HasEvents zoomed, Typeable m, Typeable base) => ActionT base zoomed m a -> ActionT base zoomed m ()
+afterInit action = void $ addListener (const (void action) :: AfterInit -> ActionT base zoomed m ())
 
 -- | Registers an action to be performed BEFORE each event phase.
-beforeEvent :: App a -> App ListenerId
-beforeEvent action = addListener (const (void action) :: BeforeEvent -> App ())
+beforeEvent :: forall base zoomed m a. (Monad m, HasEvents zoomed, Typeable m, Typeable base) => ActionT base zoomed m a -> ActionT base zoomed m ListenerId
+beforeEvent action = addListener (const (void action) :: BeforeEvent -> ActionT base zoomed m ())
 
-beforeEvent_ :: App a -> App ()
+beforeEvent_ :: (Monad m, HasEvents zoomed, Typeable m, Typeable base) => ActionT base zoomed m a -> ActionT base zoomed m ()
 beforeEvent_ = void . beforeEvent
 
 -- | Registers an action to be performed BEFORE each event phase.
-afterEvent :: App a -> App ListenerId
-afterEvent action = addListener (const (void action) :: AfterEvent -> App ())
+afterEvent :: forall base zoomed m a. (Monad m, HasEvents zoomed, Typeable m, Typeable base) => ActionT base zoomed m a -> ActionT base zoomed m ListenerId
+afterEvent action = addListener (const (void action) :: AfterEvent -> ActionT base zoomed m ())
 
-afterEvent_ :: App a -> App ()
+afterEvent_ :: (Monad m, HasEvents zoomed, Typeable m, Typeable base) => ActionT base zoomed m a -> ActionT base zoomed m ()
 afterEvent_ = void . afterEvent
 
-onExit :: App a -> App ()
-onExit action = void $ addListener (const $ void action :: Exit -> App ())
+onExit :: forall base zoomed m a. (HasEvents zoomed, Typeable m, Typeable base, Monad m) => ActionT base zoomed m a -> ActionT base zoomed m ()
+onExit action = void $ addListener (const $ void action :: Exit -> ActionT base zoomed m ())
 
 dispatchEvent
   :: forall result eventType m s.
@@ -147,15 +148,18 @@
 -- registered for the resulting event will still be run syncronously, only the
 -- code which generates the event is asynchronous.
 dispatchEventAsync
-  :: (Typeable event)
-  => IO event -> App ()
+  :: (Typeable event
+     ,MonadIO m
+     ,Typeable m
+     ,HasEvents base
+     ) => IO event -> ActionT base zoomed m ()
 dispatchEventAsync ioEvent = dispatchActionAsync $ dispatchEvent <$> ioEvent
 
 -- | A wrapper around event listeners so they can be stored in 'Listeners'.
 data Listener where
         Listener ::
             (MonadState s m, Typeable m, Typeable eventType, Typeable result,
-             Monoid result, HasExts s) =>
+             Monoid result, HasStates s) =>
             TypeRep -> ListenerId -> (eventType -> m result) -> Listener
 
 instance Show Listener where
@@ -175,7 +179,7 @@
 -- | A map of event types to a list of listeners for that event
 type Listeners = M.Map TypeRep [Listener]
 
--- | Store the listeners in extensions
+-- | Store the listeners in the state-map
 data LocalListeners =
   LocalListeners Int
                  Listeners
@@ -185,9 +189,9 @@
   def = LocalListeners 0 M.empty
 
 localListeners
-  :: HasExts s
+  :: HasStates s
   => Lens' s LocalListeners
-localListeners = ext
+localListeners = stateLens
 
 -- | This extracts all event listeners from a map of listeners which match the type of the provided event.
 matchingListeners
@@ -212,7 +216,7 @@
 type Dispatcher = forall event. Typeable event =>
                                 event -> IO ()
 
--- | This allows long-running IO processes to provide Events to the App asyncronously.
+-- | This allows long-running IO processes to provide Events to the ActionT base zoomed m asyncronously.
 --
 -- Don't let the type signature confuse you; it's much simpler than it seems.
 --
@@ -238,9 +242,9 @@
 -- > myAction :: Action s ()
 -- > myAction = onInit $ asyncEventProvider myTimer
 asyncEventProvider
-  :: (Dispatcher -> IO ()) -> App ()
+  :: (HasEvents base, MonadIO m, Typeable m) => (Dispatcher -> IO ()) -> ActionT base zoomed m ()
 asyncEventProvider asyncEventProv = asyncActionProvider $ eventsToActions asyncEventProv
   where
-    eventsToActions :: (Dispatcher -> IO ()) -> (App () -> IO ()) -> IO ()
+    eventsToActions :: (Monad m, HasEvents base, Typeable m) => (Dispatcher -> IO ()) -> (AppT base m () -> IO ()) -> IO ()
     eventsToActions aEventProv dispatcher =
       aEventProv (dispatcher . dispatchEvent)
diff --git a/src/Eve/Internal/Run.hs b/src/Eve/Internal/Run.hs
--- a/src/Eve/Internal/Run.hs
+++ b/src/Eve/Internal/Run.hs
@@ -1,22 +1,32 @@
 module Eve.Internal.Run
   ( eve
+  , eveT
   ) where
 
 import Eve.Internal.Actions
+import Eve.Internal.AppState
 import Eve.Internal.Listeners
 import Eve.Internal.Events
+import Eve.Internal.States()
 
+import Control.Monad
 import Control.Monad.State
+import Control.Lens
+import Data.Default
 import Data.Maybe
+import Data.Typeable
 
 import Pipes
 import Pipes.Concurrent
 import qualified Pipes.Parse as PP
 
-eve :: App () -> IO AppState
-eve initialize = do
-  (output, input) <- spawn unbounded
-  execApp (AppState mempty output) $ do
+eve :: App () -> IO ()
+eve = void . eveT def
+
+eveT :: (MonadIO m, Typeable m, HasEvents base) => base -> AppT base m () -> m base
+eveT startState initialize = do
+  (output, input) <- liftIO $ spawn unbounded
+  execApp (startState & asyncQueue .~ Just output) $ do
     initialize
     dispatchEvent_ Init
     dispatchEvent_ AfterInit
@@ -27,7 +37,7 @@
 -- | This is the main event loop, it runs recursively forever until something
 -- sets the exit status. It runs the pre-event listeners, then checks if any
 -- async events have finished, then runs the post event listeners and repeats.
-eventLoop :: Producer (App ()) IO () -> App ()
+eventLoop :: (MonadIO m, HasEvents base, Typeable m) => Producer (AppT base m ()) IO () -> AppT base m ()
 eventLoop producer = do
   dispatchEvent_ BeforeEvent
   (mAction, nextProducer) <- liftIO $ PP.runStateT PP.draw producer
diff --git a/src/Eve/Internal/States.hs b/src/Eve/Internal/States.hs
new file mode 100644
--- /dev/null
+++ b/src/Eve/Internal/States.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Eve.Internal.States
+  ( States
+  , HasStates(..)
+  , HasEvents
+  , stateLens
+  ) where
+
+import Control.Lens
+import Data.Map
+import Unsafe.Coerce
+import Data.Maybe
+import Data.Typeable
+import Data.Default
+
+-- | A wrapper to allow storing types of states in the same place.
+data StateWrapper =
+  forall s. (Typeable s, Show s) =>
+              StateWrapper s
+
+instance Show StateWrapper where
+  show (StateWrapper s) = show s
+
+-- | A map of state types to their current value.
+type States = Map TypeRep StateWrapper
+
+-- | Represents a state which can itself store more states.
+class HasStates s  where
+-- | This lens points to a given state's 'States' map.
+  states :: Lens' s States
+
+-- | A typeclass to ensure people don't dispatch events to states which shouldn't
+--   accept them.
+--
+-- To allow dispatching events in an action over your state simply define the
+-- empty instance:
+--
+-- > instance HasEvents MyState where
+-- -- Don't need anything here.
+class (Typeable s, HasStates s) =>
+      HasEvents s
+
+-- | A polymorphic lens which accesses stored states.
+-- It returns the default value ('def') if a state has not yet been set.
+stateLens
+  :: forall a e.
+    (Show a, Typeable a, Default a, HasStates e)
+  => Lens' e a
+stateLens = lens getter setter
+  where
+    getter s =
+      fromMaybe def $ s ^. states . at (typeRep (Proxy :: Proxy a)) . mapping coerce
+    setter s new =
+      set (states . at (typeRep (Proxy :: Proxy a)) . mapping coerce) (Just new) s
+    coerce = iso (\(StateWrapper x) -> unsafeCoerce x) StateWrapper
diff --git a/src/Eve/Internal/Testing.hs b/src/Eve/Internal/Testing.hs
deleted file mode 100644
--- a/src/Eve/Internal/Testing.hs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Eve.Internal.Testing
-  ( AppState(..)
-  , Exiting(..)
-  , noEventTest
-  ) where
-
-import Eve
-import Eve.Internal.Actions
-import Eve.Internal.Events
-import Pipes.Concurrent
-
-noEventTest :: App a -> IO a
-noEventTest test = do
-  (output, input) <- spawn unbounded
-  execApp (AppState mempty output) $ test
diff --git a/src/Eve/Testing.hs b/src/Eve/Testing.hs
new file mode 100644
--- /dev/null
+++ b/src/Eve/Testing.hs
@@ -0,0 +1,13 @@
+module Eve.Testing
+  ( noIOTest
+  ) where
+
+import Eve.Internal.Actions
+import Eve.Internal.Run
+import Eve.Internal.AppState
+
+import Control.Monad.Identity
+import Data.Default
+
+noIOTest :: AppT AppState Identity a -> (a, AppState)
+noIOTest = runIdentity . runApp def
diff --git a/test/Eve/Internal/ActionsSpec.hs b/test/Eve/Internal/ActionsSpec.hs
--- a/test/Eve/Internal/ActionsSpec.hs
+++ b/test/Eve/Internal/ActionsSpec.hs
@@ -4,36 +4,38 @@
 
 import Fixtures
 import Eve
-import Eve.Internal.Testing
 import Eve.Internal.Actions
 
 import Control.Lens
 import Control.Monad.State
 
-appendEx  :: Action String ()
+appendEx  :: Monad m => ActionT AppState String m ()
 appendEx  = modify (++ "!!")
 
+liftActionTest :: Monad m => ActionT AppState String m String
+liftActionTest = do
+  put "new"
+  liftAction $ runAction stateLens appendEx
+  get
+
 spec :: Spec
 spec = do
   describe "Exiting" $ do
-    exiting <- runIO . noEventTest $ exit >> isExiting
     it "Exits" $
-      exiting `shouldBe` True
+      let (didExit, _) = noIOTest (exit >> isExiting)
+       in didExit `shouldBe` True
 
   describe "runAction " $ do
-    runActionResult <- runIO . noEventTest $ runAction ext (put "new" >> appendEx) >> runAction ext get
     it "runs lifted actions to zoomed monad" $
-      runActionResult `shouldBe` "new!!"
+      let (runActionResult, _) = noIOTest $ runAction stateLens (put "new" >> appendEx) >> runAction stateLens get
+       in runActionResult `shouldBe` "new!!"
 
-    traversalResult <- runIO . noEventTest $ runAction ext (put $ Just "new") >> runAction (ext._Just) (appendEx >> get)
     it "runs over traversals" $
-      traversalResult `shouldBe` "new!!"
+      let (traversalResult, _) = noIOTest $ runAction stateLens (put $ Just "new") >> runAction (stateLens._Just) (appendEx >> get)
+       in traversalResult `shouldBe` "new!!"
 
   describe "liftAction" $ do
-    liftActionResult <- runIO . noEventTest . runAction ext $ do
-      put "new" 
-      liftAction $ runAction ext appendEx
-      get
     it "runs lifted actions to zoomed monad" $
-      liftActionResult `shouldBe` "new!!"
+      let (liftActionResult, _) = noIOTest (runAction stateLens liftActionTest :: AppT AppState Identity String)
+       in liftActionResult `shouldBe` "new!!"
 
diff --git a/test/Eve/Internal/AsyncSpec.hs b/test/Eve/Internal/AsyncSpec.hs
--- a/test/Eve/Internal/AsyncSpec.hs
+++ b/test/Eve/Internal/AsyncSpec.hs
@@ -15,11 +15,10 @@
 spec :: Spec
 spec = do
   describe "asyncActionProvider" $ do
-    asyncState <- runIO $ eve (asyncActionProvider (\d -> d (store .= "new" >> exit)))
+    asyncState <- ioTest (asyncActionProvider (\d -> d (store .= "new" >> exit)))
     it "Eventually Runs Provided Actions" $
       (asyncState ^. store) `shouldBe` "new"
   describe "dispatchActionAsync" $ do
-    asyncState <- runIO $ eve (asyncActionProvider (\d -> d (store .= "new" >> exit)))
-    asyncActionsResult <- runIO $ eve asyncActionsTest
+    asyncActionsResult <- ioTest asyncActionsTest
     it "Eventually Runs Provided Actions" $
       (asyncActionsResult ^. store) `shouldBe` "new"
diff --git a/test/Eve/Internal/ListenersSpec.hs b/test/Eve/Internal/ListenersSpec.hs
--- a/test/Eve/Internal/ListenersSpec.hs
+++ b/test/Eve/Internal/ListenersSpec.hs
@@ -9,13 +9,11 @@
 import Control.Monad.State
 import Control.Lens
 
-testAction :: State ExtState () -> ExtState
-testAction = flip execState emptyExts
-
-basicAction :: State ExtState ()
+basicAction :: AppT AppState Identity String
 basicAction = do
-  addListener (const (store .= "new") :: CustomEvent -> State ExtState ())
+  addListener (const (store .= "new") :: CustomEvent -> AppT AppState Identity ())
   dispatchEvent_ CustomEvent
+  use store
 
 delayedExit :: App ()
 delayedExit = do
@@ -23,11 +21,12 @@
   dispatchEventAsync (return CustomEvent)
   store .= "new"
 
-removeListenersTest :: State ExtState ()
+removeListenersTest :: AppT AppState Identity String
 removeListenersTest = do
-  listId <- addListener (const (store .= "new") :: CustomEvent -> State ExtState ())
+  listId <- addListener (const (store .= "new") :: CustomEvent -> AppT AppState Identity ())
   removeListener listId
   dispatchEvent_ CustomEvent
+  use store
 
 asyncEventsTest :: App ()
 asyncEventsTest = do
@@ -45,14 +44,14 @@
 spec :: Spec
 spec = do
   describe "dispatchEvent/addListener" $
-    it "Triggers Listeners" $ (testAction basicAction ^. store) `shouldBe` "new"
+    it "Triggers Listeners" $ fst (noIOTest basicAction) `shouldBe` "new"
   describe "dispatchEventAsync" $ do
-    delayedExitState <- runIO $ eve delayedExit
+    delayedExitState <- ioTest delayedExit
     it "Triggers Listeners Eventually" $ (delayedExitState ^. store) `shouldBe` "new"
   describe "removeListener" $
-    it "Removes Listeners" $ (testAction removeListenersTest ^. store) `shouldBe` "default"
+    it "Removes Listeners" $ fst (noIOTest removeListenersTest) `shouldBe` "default"
   describe "asyncEventProvider" $ do
-    asyncEventsResult <- runIO $ eve asyncEventsTest
+    asyncEventsResult <- ioTest asyncEventsTest
     it "Provides events eventually" $ (asyncEventsResult ^. store) `shouldBe` "new"
-    multiAsyncEventsResult <- runIO $ eve multiAsyncEventsTest
+    multiAsyncEventsResult <- ioTest multiAsyncEventsTest
     it "Can provide different event types" $ (multiAsyncEventsResult ^. store) `shouldBe` "new"
diff --git a/test/Eve/Internal/RunSpec.hs b/test/Eve/Internal/RunSpec.hs
--- a/test/Eve/Internal/RunSpec.hs
+++ b/test/Eve/Internal/RunSpec.hs
@@ -4,22 +4,18 @@
 import Test.Hspec
 import Fixtures
 import Eve
-import Eve.Internal.Testing
+import Eve.Internal.Actions
 import Control.Lens
 
 exiter :: (App () -> IO ()) -> IO ()
 exiter dispatch = dispatch exit
 
-runWithInit :: App () -> SpecM a AppState
-runWithInit next = runIO $ eve (next >> asyncActionProvider exiter)
-
 spec :: Spec
 spec = do
   describe "Running App" $ do
-    initializeState <- runWithInit (store .= "new")
     it "Initializes" $
-      (initializeState ^. store) `shouldBe` "new"
+      fst (noIOTest (store .= "new" >> use store)) `shouldBe` "new"
 
-    asyncState <- runIO $ eve (asyncActionProvider (\d -> d (store .= "new" >> exit)))
+    asyncResult <- ioTest (asyncActionProvider (\d -> d (store .= "new" >> exit)))
     it "Collects Async Actions" $
-      (asyncState ^. store) `shouldBe` "new"
+      (asyncResult ^. store) `shouldBe` "new"
diff --git a/test/Fixtures.hs b/test/Fixtures.hs
--- a/test/Fixtures.hs
+++ b/test/Fixtures.hs
@@ -1,39 +1,36 @@
 {-# language TemplateHaskell #-}
 module Fixtures
-  ( ExtState(..)
-  , store
+  ( store
   , CustomEvent(..)
-  , emptyExts
+  , noIOTest
+  , ioTest
   ) where
 
-import Eve.Internal.Extensions
+import Eve.Testing
+import Eve.Internal.States
 import Eve.Internal.Listeners
+import Eve.Internal.Actions
+import Eve.Internal.AppState
+import Eve.Internal.Run
 
 import Control.Lens
 import Data.Default
 
-data ExtState = ExtState
-  { _testExts :: Exts
-  }
-
-makeLenses ''ExtState
-
-instance HasExts ExtState where
-  exts = testExts
-
-instance HasEvents ExtState
-
-emptyExts = ExtState mempty
+import Test.Hspec.Core.Spec (SpecM)
+import Test.Hspec
 
-data Store = Store 
+data Store = Store
   {_payload :: String
   } deriving (Show, Eq)
 makeLenses ''Store
 
-store :: HasExts s => Lens' s String
-store = ext.payload
+store :: HasStates s => Lens' s String
+store = stateLens.payload
 
 instance Default Store where
   def = Store "default"
 
 data CustomEvent = CustomEvent
+
+ioTest :: App () -> SpecM m AppState
+ioTest = runIO . eveT def
