diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for freer-simple-profiling
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Co—Star Astrology, Ben Weitzman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,1 @@
+# freer-simple-profiling
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/freer-simple-profiling.cabal b/freer-simple-profiling.cabal
new file mode 100644
--- /dev/null
+++ b/freer-simple-profiling.cabal
@@ -0,0 +1,58 @@
+-- This file has been generated from package.yaml by hpack version 0.28.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 8e02280851791e0ab62db7b1821da498d030b754d37d86fa6937f21a9ee5cd8f
+
+name:           freer-simple-profiling
+version:        0.1.0.0
+synopsis:       Automatic profling of freer-simple programs
+description:    Please see the README on GitHub at <https://gitlab.com/costar-astrology/freer-simple-contrib/tree/master/freer-simple-http>
+category:       Control, Benchmarking, Profiling
+author:         Ben Weitzman
+maintainer:     ben@costarastrology.com
+copyright:      2018 Ben Weitzman
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+extra-source-files:
+    ChangeLog.md
+    README.md
+
+source-repository head
+  type: git
+  location: https://gitlab.com/costar-astrology/freer-simple-contrib/tree/master/freer-simple-http
+
+library
+  exposed-modules:
+      Control.Monad.Freer.Profiling
+  other-modules:
+      Paths_freer_simple_profiling
+  hs-source-dirs:
+      src
+  default-extensions: GADTs FlexibleContexts TypeOperators DataKinds StandaloneDeriving DeriveDataTypeable MultiParamTypeClasses FlexibleInstances UndecidableInstances TypeApplications ScopedTypeVariables TypeFamilies RankNTypes DeriveAnyClass OverloadedStrings FunctionalDependencies ConstraintKinds EmptyCase BangPatterns
+  build-depends:
+      base >=4.7 && <5
+    , containers >=0.5 && <0.6
+    , freer-simple >=1.1 && <1.2
+    , time >=1.8 && <1.9
+  default-language: Haskell2010
+
+test-suite freer-simple-profiling-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Paths_freer_simple_profiling
+  hs-source-dirs:
+      test
+  default-extensions: GADTs FlexibleContexts TypeOperators DataKinds StandaloneDeriving DeriveDataTypeable MultiParamTypeClasses FlexibleInstances UndecidableInstances TypeApplications ScopedTypeVariables TypeFamilies RankNTypes DeriveAnyClass OverloadedStrings FunctionalDependencies ConstraintKinds EmptyCase BangPatterns
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , containers >=0.5 && <0.6
+    , freer-simple >=1.1 && <1.2
+    , freer-simple-profiling
+    , hspec
+    , time >=1.8 && <1.9
+  default-language: Haskell2010
diff --git a/src/Control/Monad/Freer/Profiling.hs b/src/Control/Monad/Freer/Profiling.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/Freer/Profiling.hs
@@ -0,0 +1,105 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+
+{-|
+Module      : Control.Monad.Freer.Profiling
+Description : Automatic profiling of freer-simple effects
+Copyright   : (c) Ben Weitzman 2018
+License     : MIT
+Maintainer  : ben@costarastrolgoy.com
+Stability   : experimental
+Portability : POSIX
+-}
+
+module Control.Monad.Freer.Profiling
+  (profileEffect
+  ,Named   
+  ,SingleEffectStats(..)
+  ,EffectStats(..)
+  ,forEachStat
+  ,drawEffectStats
+  )
+where 
+
+import Control.Monad
+import Control.Monad.Freer
+import Control.Monad.Freer.Writer
+import Data.Map (Map)
+import qualified Data.Map as M
+import Data.Tree (Forest)
+import qualified Data.Tree as T
+import Data.Monoid
+import Data.Time.Clock.POSIX
+import Text.Printf
+
+-- | The stats relating to a single effect. Includes the number of times run and the
+-- total amount of time spent running.
+data SingleEffectStats = SingleEffectStats
+  { effectStatCount :: Int
+  , effectStatTime  :: Double
+  } deriving (Show)
+
+
+instance Semigroup SingleEffectStats where
+    (SingleEffectStats a x) <> (SingleEffectStats b y) = SingleEffectStats (a + b) (x + y)  
+
+instance Monoid SingleEffectStats where
+    mempty = SingleEffectStats 0 0
+
+-- | The stats for a whole bunch of effects
+newtype EffectStats = EffectStats (Map String (Map String SingleEffectStats)) deriving Show
+
+instance Semigroup EffectStats where
+    (EffectStats l) <> (EffectStats r) = EffectStats $ M.unionWith (M.unionWith mappend) l r  
+
+instance Monoid EffectStats where
+    mempty = EffectStats M.empty
+
+-- | 'Named' is a typeclass that defines the type names and constructor names for effects.
+-- Effects are defined as GADTs, and unfortunately, GADTs don't work well with 'GHC.Generics'
+-- or 'Data.Data', so this is a small typeclass that can be implemented manually to provide
+-- the info the profiler needs.
+class Named f where
+    getDataTypeName :: f a -> String
+    getConstructorName :: f a -> String
+
+-- | Iterate through each indivudal stat 
+forEachStat :: Monad m
+            => EffectStats
+            -> (String -> String -> SingleEffectStats -> m ())
+            -> m ()
+forEachStat (EffectStats stats) f = void $
+    flip M.traverseWithKey stats $ \effect actions ->
+        M.traverseWithKey (f effect) actions
+
+
+toTree :: EffectStats -> Forest String
+toTree (EffectStats m) = (\(a, b) -> T.Node a $ toSubtree b) <$> M.assocs m
+    where
+      toSubtree :: Map String SingleEffectStats -> Forest String
+      toSubtree s = (\(a, b) -> T.Node (printed a b) []) <$> M.assocs s
+
+      printed :: String -> SingleEffectStats -> String
+      printed action (SingleEffectStats n t) = printf "%s: Ran %d time, taking %0.3f seconds" action n t
+
+-- | Pretty print the effect stats
+drawEffectStats :: EffectStats -> String
+drawEffectStats = T.drawForest . toTree    
+
+
+-- | Automatically time and count each individual effectful compoutation. An effect that
+-- is interpreted to another effect will count towards both effects, flame graph style. 
+profileEffect :: forall q r v
+               . (Member (Writer EffectStats) r, Member IO r, Member q r, Named q)
+              => Eff r v -> Eff r v
+profileEffect eff = interpose handleEff eff
+  where
+    handleEff :: q a -> Eff r a
+    handleEff action = do
+      !start <- realToFrac <$> send getPOSIXTime
+      v <- send action
+      !end <- realToFrac <$> send getPOSIXTime
+      let !diff = end - start
+          effectName = getDataTypeName action
+          actionName = getConstructorName action
+      tell $ EffectStats (M.singleton effectName $ M.singleton actionName (SingleEffectStats 1 diff))
+      return v
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"
