diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, Jonathan Fischoff
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Jonathan Fischoff nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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/async-manager.cabal b/async-manager.cabal
new file mode 100644
--- /dev/null
+++ b/async-manager.cabal
@@ -0,0 +1,39 @@
+-- Initial async-manager.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                async-manager
+version:             0.1.0.0
+synopsis:            A thread manager for async
+description:         Cleanup and kill async threads.
+homepage:            http://github.com/jfischoff/async-manager
+license:             BSD3
+license-file:        LICENSE
+author:              Jonathan Fischoff
+maintainer:          jonathangfischoff@gmail.com
+-- copyright:           
+category:            Concurrency
+build-type:          Simple
+-- extra-source-files:  
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     Control.Concurrent.AsyncManager
+  -- other-modules:       
+  other-extensions:    ExistentialQuantification
+  build-depends: base >=4.7 && <4.8
+               , async >=2.0 && <2.1
+               , stm >=2.4 && <2.5
+               , unordered-containers >=0.2 && <0.3
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+
+executable thread-clean-up-test
+  main-is: ThreadCleanupTest.hs
+  build-depends: base >=4.7 && <4.8
+               , async >=2.0 && <2.1
+               , stm >=2.4 && <2.5
+               , unordered-containers >=0.2 && <0.3
+  hs-source-dirs: src, tests
+  default-language: Haskell2010
+  
+  ghc-options: -threaded -eventlog -rtsopts -with-rtsopts=-l
diff --git a/src/Control/Concurrent/AsyncManager.hs b/src/Control/Concurrent/AsyncManager.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Concurrent/AsyncManager.hs
@@ -0,0 +1,82 @@
+{-# LANGUAGE ExistentialQuantification #-}
+module Control.Concurrent.AsyncManager where
+import Control.Concurrent
+import Control.Concurrent.Async
+import Control.Concurrent.STM
+import Control.Concurrent.MVar
+import Data.IORef
+import Control.Monad
+import Data.Foldable (toList)
+import Data.HashMap.Strict (HashMap)
+import qualified Data.HashMap.Strict as H
+import Data.Monoid
+import Data.Maybe
+import Control.Applicative
+import Control.Arrow (second)
+import GHC.Conc
+
+-- | A existentially quantified wrapper for Async a
+data AnyAsync = forall a. AnyAsync (Async a) 
+
+-- | An Async thread manager. Keeps track of allocated and running
+--   Async threads. Useful for ensure threads are cleaned up
+newtype AsyncManager = AsyncManager { unAsyncManager :: MVar (HashMap ThreadId AnyAsync) }
+
+-- | Create a new empty manager
+newAsyncManager :: IO AsyncManager
+newAsyncManager = AsyncManager <$> newMVar mempty
+
+-- | Insert a new thread into the manager
+--   TODO: maybe I should check if the computation is still running
+insert :: AsyncManager -> Async a -> IO ()
+insert (AsyncManager ref) as 
+  = modifyMVar_ ref 
+  $ return . (H.insert (asyncThreadId as) (AnyAsync as))
+  
+-- | Cancel all threads and empty the manager
+clear :: AsyncManager -> IO ()
+clear (AsyncManager ref) = modifyMVar_ ref $ \xs -> do
+   forM_ (toList xs) $ \(AnyAsync x) -> cancel x
+   return mempty
+
+-- | Thread count. Includes alive and dead threads
+count :: AsyncManager -> IO Int
+count (AsyncManager ref) = H.size <$> readMVar ref
+
+-- | Remove references to dead threads
+compact :: AsyncManager -> IO ()
+compact (AsyncManager ref) = modifyMVar_ ref $ 
+  fmap H.fromList . filterM ((\(AnyAsync x) -> isJust <$> poll x) . snd) . H.toList
+
+-- | Cancel the thread and remove the entry from the manager
+cancelWithManager :: AsyncManager 
+                  -> Async a
+                  -> IO ()
+cancelWithManager (AsyncManager ref) as = do
+  cancel as
+  modifyMVar_ ref $ return . H.delete (asyncThreadId as)
+
+-- | Create a new thread and add it to the manager
+asyncWithManager :: AsyncManager 
+                 -> IO a 
+                 -> IO (Async a)
+asyncWithManager am act = do
+  result <- async act
+  insert am result 
+  return result
+  
+labelAsyncWithManager :: AsyncManager
+                      -> String
+                      -> IO a
+                      -> IO (Async a)
+labelAsyncWithManager am label act = do
+  as <- asyncWithManager am act
+  labelThread (asyncThreadId as) label 
+  return as
+  
+
+
+
+
+
+
diff --git a/tests/ThreadCleanupTest.hs b/tests/ThreadCleanupTest.hs
new file mode 100644
--- /dev/null
+++ b/tests/ThreadCleanupTest.hs
@@ -0,0 +1,19 @@
+module Main where
+import Control.Concurrent.AsyncManager
+import GHC.Conc
+import Debug.Trace
+import Control.Monad 
+
+main = do
+  traceEventIO "start"
+  manager <- newAsyncManager
+  traceEventIO "created manager"
+  t1 <- labelAsyncWithManager manager "test thread 1" $ forever $ return () >> threadDelay 500000
+  traceEventIO "created first thread"
+  t2 <- labelAsyncWithManager manager "test thread 2" $ forever $ return () >> threadDelay 500000
+  traceEventIO "created second thread"
+  traceEventIO "before clear"
+  clear manager
+  traceEventIO "after clear"
+  threadDelay 500000
+  traceEventIO "Done"
