diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2010, Petr Rockai <me@mornfall.net>
+
+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 Petr Rockai 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/Shelly/Background.hs b/Shelly/Background.hs
new file mode 100644
--- /dev/null
+++ b/Shelly/Background.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Shelly.Background (
+   -- * Running external commands asynchronously.
+   jobs, background, getBgResult, BgResult
+) where
+
+import Shelly
+import Control.Concurrent
+import qualified Control.Concurrent.MSem as Sem
+
+-- | Create a 'BgJobManager' that has a 'limit' on the max number of background tasks.
+-- an invocation of jobs is independent of any others, and not tied to the ShIO monad in any way.
+-- This blocks the execution of the program until all 'background' jobs are finished.
+jobs :: Int -> (BgJobManager -> ShIO a) -> ShIO a
+jobs limit action = do
+    unless (limit > 0) $ terror "expected limit to be > 0"
+    availableJobsSem <- liftIO $ Sem.new limit
+    res <- action $ BgJobManager availableJobsSem
+    liftIO $ waitForJobs availableJobsSem
+    return res
+  where
+    waitForJobs sem = do
+      avail <- Sem.peekAvail sem
+      if avail == limit then return () else waitForJobs sem
+
+-- | The manager tracks the number of jobs. Register your 'background' jobs with it.
+newtype BgJobManager = BgJobManager (Sem.MSem Int)
+
+-- | Type returned by tasks run asynchronously in the background.
+newtype BgResult a = BgResult (MVar a)
+
+-- | Returns the promised result from a backgrounded task.  Blocks until
+-- the task completes.
+getBgResult :: BgResult a -> ShIO a
+getBgResult (BgResult mvar) = liftIO $ takeMVar mvar
+
+-- | Run the `ShIO` task asynchronously in the background, returns
+-- the `BgResult a`, a promise immediately. Run "getBgResult" to wait for the result.
+-- The background task will inherit the current ShIO context
+-- The 'BjJobManager' ensures the max jobs limit must be sufficient for the parent and all children.
+background :: BgJobManager -> ShIO a -> ShIO (BgResult a)
+background (BgJobManager manager) proc = do
+  state <- get
+  liftIO $ do
+    -- take up a spot
+    -- It is important to do this before forkIO:
+    -- It ensures that that jobs will block and the program won't exit before our jobs are done
+    -- On the other hand, a user might not expect 'jobs' to block
+    Sem.wait manager
+    mvar <- newEmptyMVar -- future result
+
+    _<- forkIO $ do
+      result <- shelly $ (put state >> proc)
+      Sem.signal manager -- open a spot back up
+      liftIO $ putMVar mvar result
+    return $ BgResult mvar
+
diff --git a/shelly-extra.cabal b/shelly-extra.cabal
new file mode 100644
--- /dev/null
+++ b/shelly-extra.cabal
@@ -0,0 +1,44 @@
+Name:       shelly-extra
+
+Version:     0.2
+Synopsis:    shelly features that require extra dependencies
+
+Description: Please see the shelly package. Shelly provides a single module for convenient
+             systems programming in Haskell, similar in spirit to POSIX shells.
+             .
+             shelly-extra is designed to be a grab bag for functionality that
+               * requires extra dependencies
+             .
+               * or is application specific and not generally applicable
+             .
+             currently contains a background job implementation for performing tasks in parallel
+
+
+Homepage:            https://github.com/yesodweb/Shelly.hs
+License:             BSD3
+License-file:        LICENSE
+Author:              Greg Weber
+Maintainer:          Greg Weber <greg@gregweber.info>
+Category:            Development
+Build-type:          Simple
+Cabal-version:       >=1.8
+
+
+Library
+  Exposed-modules:     Shelly.Background
+
+  Build-depends: base >= 4 && < 5, shelly >= 0.10, SafeSemaphore
+
+  ghc-options: -Wall
+
+test-suite test
+    type:           exitcode-stdio-1.0
+    main-is:        main.hs
+    hs-source-dirs: ., test
+    ghc-options: -Wall
+
+    Build-depends: base, text, shelly, SafeSemaphore
+
+source-repository head
+  type:     git
+  location: https://github.com/yesodweb/Shelly.hs
diff --git a/test/main.hs b/test/main.hs
new file mode 100644
--- /dev/null
+++ b/test/main.hs
@@ -0,0 +1,41 @@
+{-# Language OverloadedStrings #-}
+{-# Language ExtendedDefaultRules #-}
+{-# Language ScopedTypeVariables #-}
+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
+
+import Shelly
+import Shelly.Background
+import Data.Text.Lazy (Text)
+default (Text)
+
+-- smoke tests
+main :: IO ()
+main =
+  shelly $
+    -- verbosely $
+    do
+    jobs 2 $ \job -> do
+      _<- background job $ cmd "sleep" "2"
+      echo "immediate"
+      _<- background job $ cmd "sleep" "2"
+      echo "immediate2"
+      _<- background job $ cmd "sleep" "2"
+      echo "blocked by background "
+ 
+    echo "blocked by jobs"
+
+    setStdin "in"
+    setStdin "override stdin"
+    run_ "cat" ["-"]
+
+    recho <- cmd "echo" "cmd"
+    _<-cmd "echo" "bar" "baz"
+    echo recho
+
+    (res :: Text) <- cmd "pwd"
+    liftIO $ putStrLn $ show res
+    inspect res
+
+    inspect =<< (cmd "echo" "compose" :: ShIO Text)
+    inspect =<< (cmd "pwd")
+
