diff --git a/Shelly.hs b/Shelly.hs
--- a/Shelly.hs
+++ b/Shelly.hs
@@ -12,8 +12,11 @@
          ShIO, shelly, sub, silently, verbosely, print_commands
 
          -- * Modifying and querying environment.
-         , setenv, getenv, getenv_def, cd, chdir, pwd
+         , setenv, getenv, getenv_def, appendPath
 
+         -- * Environment directory
+         , cd, chdir, pwd
+
          -- * Printing
          , echo, echo_n, echo_err, echo_n_err, inspect
 
@@ -28,7 +31,9 @@
          , readfile, writefile, appendfile, withTmpDir
 
          -- * Running external commands.
-         , run, ( # ), run_, command, command_, command1, command1_, lastStderr
+         , run, ( # ), run_, (-|-), lastStderr, setStdin
+         , command, command_, command1, command1_
+--         , Sudo(..), run_sudo
 
          -- * exiting the program
          , exit, errorExit, terror
@@ -131,6 +136,7 @@
      `catchany` \_ -> return acc
 
 data State = State   { sCode :: Int
+                     , sStdin :: Maybe Text -- ^ stdin for the command to be run
                      , sStderr :: Text
                      , sDirectory :: FilePath
                      , sVerbose :: Bool
@@ -167,6 +173,16 @@
     (Just $ unpack $ sDirectory st)
     (Just $ sEnvironment st)
 
+{-
+-- | use for commands requiring usage of sudo. see 'run_sudo'.
+--  Use this pattern for priveledge separation
+newtype Sudo a = Sudo { sudo :: ShIO a }
+
+-- | require that the caller explicitly state 'sudo'
+run_sudo :: Text -> [Text] -> Sudo Text
+run_sudo cmd args = Sudo $ run "/usr/bin/sudo" (cmd:args)
+-}
+
 -- | A helper to catch any exception (same as
 -- @... `catch` \(e :: SomeException) -> ...@).
 catchany :: IO a -> (SomeException -> IO a) -> IO a
@@ -356,6 +372,15 @@
       wibble env = (kStr, vStr) : filter ((/=kStr).fst) env
    in modify $ \x -> x { sEnvironment = wibble $ sEnvironment x }
 
+-- | add the filepath onto the PATH env variable
+appendPath :: FilePath -> ShIO ()
+appendPath filepath = do
+  tp <- toTextWarn filepath
+  pe <- getenv path_env
+  setenv path_env $ pe `mappend` ":" `mappend` tp
+  where
+    path_env = "PATH"
+
 -- | Fetch the current value of an environment variable. Both empty and
 -- non-existent variables give empty string as a result.
 getenv :: Text -> ShIO Text
@@ -380,13 +405,13 @@
 print_commands a = sub $ modify (\x -> x { sPrintCommands = True }) >> a
 
 -- | Enter a sub-ShIO that inherits the environment and working directory
--- from the current ShIO, but cannot affect the current one.
+-- The original state will be restored when the sub-ShIO completes.
  --Exceptions are propagated normally.
 sub :: ShIO a -> ShIO a
 sub a = do
-  st <- get
-  r <- a `catch_sh` (\(e :: SomeException) -> put st >> throw e)
-  put st
+  state <- get
+  r <- a `catch_sh` (\(e :: SomeException) -> put state >> throw e)
+  put state
   return r
 
 -- | Enter a ShIO from (Monad)IO. The environment and working directories are
@@ -398,6 +423,7 @@
   env <- liftIO getEnvironment
   dir <- liftIO getWorkingDirectory
   let def  = State { sCode = 0
+                   , sStdin = Nothing
                    , sStderr = LT.empty
                    , sVerbose = True
                    , sPrintCommands = False
@@ -475,7 +501,7 @@
     when (sPrintCommands state) $ do
       c <- toTextWarn cmd
       echo $ LT.intercalate " " (c:args)
-    (_,outH,errH,procH) <- sRun state cmd args
+    (inH,outH,errH,procH) <- sRun state cmd args
 
     errV <- liftIO newEmptyMVar
     outV <- liftIO newEmptyMVar
@@ -487,6 +513,13 @@
         liftIO_ $ forkIO $ getContent errH >>= putMVar errV
         liftIO_ $ forkIO $ foldHandleLines start cb outH >>= putMVar outV
 
+    -- If input was provided write it to the input handle.
+    case sStdin state of
+      Just input ->
+        liftIO $ TIO.hPutStr inH input >> hClose inH
+        -- stdin is cleared from state below
+      Nothing -> return ()
+
     errs <- liftIO $ takeMVar errV
     outs <- liftIO $ takeMVar outV
     ex <- liftIO $ waitForProcess procH
@@ -496,7 +529,8 @@
                  ExitSuccess -> 0
                  ExitFailure n -> n
     put $ state {
-       sStderr = errs
+       sStdin = Nothing
+     , sStderr = errs
      , sCode = code
     }
     case ex of
@@ -506,6 +540,17 @@
 -- | The output of last external command. See "run".
 lastStderr :: ShIO Text
 lastStderr = gets sStderr
+
+-- | set the stdin to be used and cleared by the next "run".
+setStdin :: Text -> ShIO ()
+setStdin input = modify $ \st -> st { sStdin = Just input }
+
+-- | set the output of the first command as the stdin of the second.
+(-|-) :: ShIO Text -> ShIO b -> ShIO b
+one -|- two = do
+  res <- one
+  setStdin res
+  two
 
 data MemTime = MemTime Rational Double deriving (Read, Show, Ord, Eq)
 
diff --git a/shelly.cabal b/shelly.cabal
--- a/shelly.cabal
+++ b/shelly.cabal
@@ -1,6 +1,6 @@
 Name:       shelly
 
-Version:     0.3.1
+Version:     0.4
 Synopsis:    shell-like (systems) programming in Haskell
 
 Description: Shelly is a package provides a single module for convenient
@@ -25,12 +25,10 @@
 Maintainer:          Greg Weber <greg@gregweber.info>
 Category:            Development
 Build-type:          Simple
-Cabal-version:       >=1.6
+Cabal-version:       >=1.8
 
--- Extra-source-files:
 
 Library
-  -- Modules exported by the library.
   Exposed-modules:     Shelly
 
   Build-depends: base >= 4 && < 5, time, directory, mtl, process, text, unix-compat
@@ -38,11 +36,19 @@
 
   ghc-options: -Wall
 
+test-suite test
+    type:           exitcode-stdio-1.0
+    main-is:        main.hs
+    hs-source-dirs: ., test
+
+    build-depends:   base >= 4 && < 5
+                   -- , hspec
+
 -- demonstarated that command output in Shellish was not shown until after the command finished
 -- not necessary anymore
 -- Executable drain
 --  main-is: test/drain.hs
 
 source-repository head
-  type:     darcs
-  location: http://repos.mornfall.net/shelly
+  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,10 @@
+{-# Language OverloadedStrings #-}
+import Shelly
+
+main :: IO ()
+main =
+  shelly $ do
+    setStdin "in"
+    echo "echo"
+    setStdin "catted"
+    run_ "cat" ["-"]
