diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2013, kartoffelbrei
+
+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 kartoffelbrei 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/pipes-shell.cabal b/pipes-shell.cabal
new file mode 100644
--- /dev/null
+++ b/pipes-shell.cabal
@@ -0,0 +1,107 @@
+-- Initial pipes-shell.cabal generated by cabal init.  For further
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+-- The name of the package.
+name:                pipes-shell
+
+version:             0.1.0
+
+-- A short (one-line) description of the package.
+synopsis:             Create proper Pipes from System.Process
+
+-- A longer description of the package.
+description:          This package provide functions to build proper Pipes from Unix shell commands like /tr/, /ls/ or /echo/ in a concise way.
+                      .
+                      Build with /cabal configure --enable-tests/ to build the little hspec test.
+
+-- The license under which the package is released.
+license:             BSD3
+
+-- The file containing the license text.
+license-file:        LICENSE
+
+-- The package author(s).
+author:              kartoffelbrei
+
+-- An email address to which users can send suggestions, bug reports, and
+-- patches.
+maintainer:          kartoffelbrei.mit.muskatnuss@gmail.com
+
+bug-reports: https://github.com/kbrei/pipes-shell/issues
+
+
+-- A copyright notice.
+copyright:     2013 Lars Schulna
+
+category: Pipes
+
+build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or a
+-- README.
+-- extra-source-files:
+
+-- Constraint on the version of Cabal needed to build this package.
+cabal-version:       >=1.10
+
+source-repository head
+  type: git
+  location: git://github.com/kbrei/pipes-shell.git
+
+library
+  -- Modules exported by the library.
+  exposed-modules:     Pipes.Shell
+
+  -- Modules included in this library but not exported.
+  -- other-modules:
+
+  -- LANGUAGE extensions used by modules in this package.
+  -- other-extensions:
+
+  -- Other library packages from which modules are imported.
+  build-depends:       base >=4.6 && <4.7,
+                       stm >=2.4 && <2.5,
+                       process >=1.1 && <1.2,
+                       pipes >= 4.0.1 && <5,
+                       pipes-safe >= 2.0.1 && <3,
+                       pipes-bytestring >= 1.0.1 && <2,
+                       text >= 0.11.3.0 && <0.12,
+                       bytestring >= 0.10.0.2 && <0.11,
+                       async >= 2.0.1.0 && <2.1,
+                       stm-chans >= 3.0.0 && <3.1
+
+  -- Directories containing source files.
+  hs-source-dirs:      src
+
+  -- Base language which the package is written in.
+  default-language:    Haskell2010
+
+test-suite spec
+  type:            exitcode-stdio-1.0
+  main-is:         Spec.hs
+
+  -- Modules included in this library but not exported.
+  -- other-modules:
+
+  -- LANGUAGE extensions used by modules in this package.
+  -- other-extensions:
+
+  -- Other library packages from which modules are imported.
+  build-depends:   base >=4.6 && <4.7,
+                   stm >=2.4 && <2.5,
+                   process >=1.1 && <1.2,
+                   pipes >= 4.0.1 && <5,
+                   pipes-safe >= 2.0.1 && <3,
+                   pipes-bytestring >= 1.0.1 && <2,
+                   text >= 0.11.3.0 && <0.12,
+                   bytestring >= 0.10.0.2 && <0.11,
+                   async >= 2.0.1.0 && <2.1,
+                   stm-chans >= 3.0.0 && <3.1,
+                   hspec >= 1.7.2.0 && <1.8
+
+  -- Directories containing source files.
+  hs-source-dirs:  src, test
+
+  -- Base language which the package is written in.
+  default-language:    Haskell2010
+  ghc-options:         -Wall
diff --git a/src/Pipes/Shell.hs b/src/Pipes/Shell.hs
new file mode 100644
--- /dev/null
+++ b/src/Pipes/Shell.hs
@@ -0,0 +1,315 @@
+{-# LANGUAGE FlexibleContexts          #-}
+{-# LANGUAGE FlexibleInstances         #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
+{-# LANGUAGE OverlappingInstances      #-}
+{-# LANGUAGE RankNTypes                #-}
+{-# LANGUAGE TypeFamilies              #-}
+
+-- | This module contains a few functions to use unix-y shell commands
+-- as 'Pipe's.
+--
+-- The output 'ByteString's from 'pipeCmdEnv' and friends are not line-wise, but chunk-wise. To get proper lines use the pipes-binary and the upcoming pipes-text machinery.
+--
+-- All code examples in this module assume following qualified imports:
+-- Pipes.Prelude as P, Pipes.ByteString as PBS, Data.ByteString.Char8 as BSC
+
+module Pipes.Shell
+  (
+
+  -- * Basic combinators
+    pipeCmdEnv,     pipeCmd,     pipeCmd'
+  , producerCmdEnv, producerCmd, producerCmd'
+  , consumerCmdEnv, consumerCmd
+
+  -- * Fancy overloads
+  , Cmd, Cmd'
+  , cmdEnv,         cmd,         cmd'
+
+  -- * Utils
+  , (>?>)
+  , markEnd
+  , ignoreErr, ignoreOut
+  , runShell
+  ) where
+
+import           Control.Monad
+import           Pipes
+import qualified Pipes.ByteString               as PBS
+import           Pipes.Core
+import qualified Pipes.Prelude                  as P
+import           Pipes.Safe                     hiding (handle)
+
+import           Control.Concurrent             hiding (yield)
+import           Control.Concurrent.Async
+import           Control.Concurrent.STM
+import           Control.Concurrent.STM.TBMChan
+import qualified System.IO                      as IO
+import           System.Process
+
+import qualified Data.ByteString                as BS
+
+-- Fancy overloads
+
+-- | An ad-hoc typeclass to get the varadic arguments and DWIM behavoir of 'cmdEnv'
+class Cmd cmd where
+  -- | Like 'pipeCmdEnv', 'producerCmdEnv' or 'consumerCmdEnv' depending on the context.
+  -- It also supports varadic arguments.
+  --
+  -- Examples:
+  --
+  -- As 'Pipe':
+  --
+  -- >>> runShell $ yield (BSC.pack "aaa") >?> cmd "tr 'a' 'A'" >-> ignoreErr >-> PBS.stdout
+  -- AAA
+  --
+  -- As 'Producer':
+  --
+  -- >>> runShell $ cmd "ls" >-> ignoreErr >-> PBS.stdout
+  -- <output from ls on the current directory>
+  --
+  -- As 'Consumer':
+  --
+  -- >>> runShell $ yield (BSC.pack "aaa") >?> cmd "cat > test.file"
+  -- <a new file with "aaa" in it>
+  cmdEnv :: Maybe [(String,String)] -> String -> cmd
+
+  -- | Like 'cmdEnv' but doesn't set enviorment varaibles
+  cmd :: Cmd cmd => String -> cmd
+  cmd = cmdEnv Nothing
+
+instance Cmd cmd => Cmd (String -> cmd) where
+  cmdEnv env' binary arg = cmdEnv env' $ binary ++ " " ++ arg
+
+instance MonadSafe m =>
+         Cmd (Pipe (Maybe BS.ByteString) (Either BS.ByteString BS.ByteString) m ()) where
+  cmdEnv = pipeCmdEnv
+
+instance MonadSafe m =>
+         Cmd (Producer (Either BS.ByteString BS.ByteString) m ()) where
+  cmdEnv = producerCmdEnv
+
+instance MonadSafe m =>
+         Cmd (Consumer (Maybe BS.ByteString) m ()) where
+  cmdEnv = consumerCmdEnv
+
+
+-- | An ad-hoc typeclass to get the varadic arguments and DWIM behavoir of 'cmd''.
+-- This class is seperate from 'Cmd' to make the return types work out.
+class Cmd' cmd where
+  -- | Like 'cmd' but uses 'ignoreErr' automatically.
+  -- So it's like 'pipeCmd'', 'producerCmd'' or 'consumerCmd' depending on context.
+  -- It supports the same style of varadic arguments as 'cmd'
+  cmd' :: String -> cmd
+
+instance Cmd' cmd => Cmd' (String -> cmd) where
+  cmd' binary arg = cmd' $ binary ++ " " ++ arg
+
+instance MonadSafe m =>
+         Cmd' (Pipe (Maybe BS.ByteString) BS.ByteString m ()) where
+  cmd' = pipeCmd'
+
+instance MonadSafe m =>
+         Cmd' (Producer BS.ByteString m ()) where
+  cmd' = producerCmd'
+
+instance MonadSafe m =>
+         Cmd' (Consumer (Maybe BS.ByteString) m ()) where
+  cmd' = consumerCmd
+
+
+-- Basic combinators
+
+-- | This is the workhorse of this package.
+--
+-- It provides the direct interface from a shell command string to a proper
+-- 'Pipe'.
+--
+-- >>> runShell $ yield (BSC.pack "aaa") >?> pipeCmdEnv Nothing "tr 'a' 'A'" >-> PBS.stdout
+-- AAA
+pipeCmdEnv :: MonadSafe m =>
+           Maybe [(String,String)] ->
+           String ->
+           Pipe (Maybe BS.ByteString) (Either BS.ByteString BS.ByteString) m ()
+pipeCmdEnv env' cmdStr = bracket (aquirePipe env' cmdStr) releasePipe $
+  \(stdin, stdout, stderr) -> do
+
+    chan <- liftIO $ newTBMChanIO 4
+    _ <- liftIO $ forkIO $
+      handlesToChan stdout stderr chan
+
+    body stdin chan
+
+  where
+  body stdin chan = do
+    got <- await
+    case got of
+      Nothing -> do
+        liftIO $ IO.hClose stdin
+        fromTBMChan chan
+      Just val -> do
+        liftIO $ BS.hPutStr stdin val
+        yieldOne chan
+        body stdin chan
+
+  -- *try* to read one line from the chan and yield it.
+  yieldOne chan = do
+    mLine <- liftIO $ atomically $ tryReadTBMChan chan
+    whenJust (join mLine)
+      yield
+
+  -- fill the TBMChan from the stdout and stderr handles
+  -- the current implementation reads stderr and stdout async
+  handlesToChan stdout stderr chan = do
+    out <- async $ toTBMChan chan $ do
+           PBS.fromHandle stdout >-> P.map Right
+           liftIO $ IO.hClose stdout
+
+    err <- async $ toTBMChan chan $ do
+           PBS.fromHandle stderr >-> P.map Left
+           liftIO $ IO.hClose stderr
+
+    forM_ [out, err] wait
+
+    atomically $ closeTBMChan chan
+
+-- | Like 'pipeCmdEnv' but doesn't set enviorment varaibles
+pipeCmd :: MonadSafe m =>
+           String ->
+           Pipe (Maybe BS.ByteString) (Either BS.ByteString BS.ByteString) m ()
+pipeCmd = pipeCmdEnv Nothing
+
+-- | Like 'pipeCmd' but ignores stderr
+pipeCmd' :: MonadSafe m =>
+           String ->
+           Pipe (Maybe BS.ByteString) BS.ByteString m ()
+pipeCmd' cmdStr = pipeCmd cmdStr >-> ignoreErr
+
+-- | Like 'pipeCmdEnv' but closes the input end immediately.
+--
+-- Useful for command line tools like @ ls @
+producerCmdEnv :: MonadSafe m =>
+              Maybe [(String, String)] ->
+              String ->
+              Producer (Either BS.ByteString BS.ByteString) m ()
+producerCmdEnv env' cmdStr = yield Nothing >-> pipeCmdEnv env' cmdStr
+
+-- | Like 'producerCmdEnv' but doesn't set enviorment varaibles
+producerCmd :: MonadSafe m =>
+              String ->
+              Producer (Either BS.ByteString BS.ByteString) m ()
+producerCmd = producerCmdEnv Nothing
+
+-- | Like 'producerCmd' but ignores stderr
+producerCmd' :: MonadSafe m =>
+              String ->
+              Producer BS.ByteString m ()
+producerCmd' cmdStr = producerCmd cmdStr >-> ignoreErr
+
+-- | Like 'pipeCmd' but closes the output end immediately.
+--
+-- Useful for command line tools like @ cat > test.file @
+consumerCmdEnv:: MonadSafe m =>
+              Maybe [(String,String)] ->
+              String ->
+              Consumer (Maybe BS.ByteString) m ()
+consumerCmdEnv env' cmdStr = pipeCmdEnv env' cmdStr >-> void await
+
+-- | Like 'consumerCmdEnv' but doesn't set enviorment varaibles
+consumerCmd:: MonadSafe m =>
+              String ->
+              Consumer (Maybe BS.ByteString) m ()
+consumerCmd = consumerCmdEnv Nothing
+
+
+-- Utils
+
+-- | Like '>->' but marks the end of the left pipe with 'markEnd'.
+-- It's needed because 'pipeCmdEnv' has to know when the upstream 'Pipe' finishes.
+--
+-- The basic rule is:
+--
+-- @ Replace every '>->' with '>?>' when it's in front of 'pipeCmdEnv' or similar. @
+(>?>) :: Monad m =>
+     Proxy a' a         () b m r ->
+     Proxy () (Maybe b) c' c m r ->
+     Proxy a' a         c' c m r
+a >?> b = markEnd a >-> b
+infixl 7 >?>
+
+-- | Mark the end of a pipe.
+-- It wraps all values in a 'Just' and yields *one* 'Nothing' after the upstream pipefinished.
+markEnd :: Monad m =>
+           Proxy a' a b' b         m r ->
+           Proxy a' a b' (Maybe b) m r
+markEnd pipe = do
+  result <- for pipe (respond . Just)
+  _ <- respond Nothing
+  return result
+
+-- | Ignore stderr from a 'pipeCmd'
+ignoreErr :: (Monad m) => Pipe (Either BS.ByteString BS.ByteString) BS.ByteString m ()
+ignoreErr = forever $ do
+  val <- await
+  case val of
+    Left _ -> return ()
+    Right x -> yield x
+
+-- | Ignore stdout from a 'pipeCmd'
+ignoreOut :: (Monad m) => Pipe (Either BS.ByteString BS.ByteString) BS.ByteString m ()
+ignoreOut = forever $ do
+  val <- await
+  case val of
+    Left x -> yield x
+    Right _ -> return ()
+
+-- | A simple run function for 'Pipe's that live in 'SafeT' 'IO'
+runShell :: Effect (SafeT IO) r -> IO r
+runShell = runSafeT . runEffect
+
+
+
+-- Implementation utils
+
+whenJust :: Monad m => Maybe a -> (a -> m ()) -> m ()
+whenJust (Just x) action = action x
+whenJust Nothing _ = return ()
+
+fromTBMChan :: (MonadIO m) => TBMChan a -> Producer' a m ()
+fromTBMChan chan = do
+  msg <- liftIO $ atomically $ readTBMChan chan
+  whenJust msg $ \m -> do
+    yield m
+    fromTBMChan chan
+
+toTBMChan :: MonadIO m => TBMChan a -> Producer' a m () -> m ()
+toTBMChan chan prod = runEffect $
+  for prod (liftIO . atomically . writeTBMChan chan)
+
+-- | Creates the pipe handles
+aquirePipe :: MonadIO m =>
+              Maybe [(String, String)] ->
+              String ->
+              m (IO.Handle, IO.Handle, IO.Handle)
+aquirePipe env' cmdStr = liftIO $ do
+  (Just stdin, Just stdout, Just stderr, _) <- createProcess (shellPiped env' cmdStr)
+  return (stdin, stdout, stderr)
+
+-- | Releases the pipe handles
+releasePipe :: MonadIO m => (IO.Handle, IO.Handle, IO.Handle) -> m ()
+releasePipe (stdin, stdout, stderr) = liftIO $ do
+  IO.hClose stdin
+  IO.hClose stdout
+  IO.hClose stderr
+
+-- | Helper function to create the shell pipe handles
+shellPiped :: Maybe [(String, String)] -> String -> CreateProcess
+shellPiped env' cmdStr = CreateProcess
+    { cmdspec = ShellCommand cmdStr
+    , cwd          = Nothing
+    , env          = env'
+    , std_in       = CreatePipe
+    , std_out      = CreatePipe
+    , std_err      = CreatePipe
+    , close_fds    = False
+    , create_group = False
+    }
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
