diff --git a/Command.cabal b/Command.cabal
new file mode 100644
--- /dev/null
+++ b/Command.cabal
@@ -0,0 +1,26 @@
+Name:               Command
+Version:            0.0.1
+License:            BSD3
+License-File:       LICENSE
+Author:             Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ>
+Maintainer:         Tony Morris
+Synopsis:           A replacement for System.Exit and System.Process
+Category:           System
+Description:
+  Specifically, this library replaces @System.Exit.ExitCode@ with an abstract data type.
+Cabal-version:      >= 1.2
+Build-Type:         Simple
+
+Flag small_base
+  Description:      Choose the new, split-up base package.
+
+Library
+  Build-Depends:
+                    base < 5 && >= 4
+                    , process
+
+  GHC-Options:      -Wall
+
+  Exposed-Modules:  System.Command
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2009 Tony Morris
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 AUTHORS 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,3 @@
+import Distribution.Simple
+main = defaultMain
+
diff --git a/System/Command.hs b/System/Command.hs
new file mode 100644
--- /dev/null
+++ b/System/Command.hs
@@ -0,0 +1,274 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
+module System.Command
+(
+  -- * Running sub-processes
+  P.createProcess
+, P.shell
+, P.proc
+, P.CreateProcess(..)
+, P.CmdSpec(..)
+, P.StdStream(..)
+, P.ProcessHandle
+  -- * Specific variants of createProcess
+, readProcessWithExitCode
+, P.runCommand
+, P.runProcess
+, P.runInteractiveCommand
+, P.runInteractiveProcess
+, P.readProcess
+, system
+, rawSystem
+  -- * Data Type
+, ExitCode
+  -- * ExitCode combinators
+, exitCode
+, success
+, isSuccess
+, isFailure
+, exitValue
+, exitWith
+, exitFailure
+, exitSuccess
+, (->>)
+, (<<-)
+, runExitCodes
+  -- * Process completion
+, waitForProcess
+, getProcessExitCode
+, P.terminateProcess
+) where
+
+import qualified System.Exit as E
+import qualified System.Process as P
+import Data.Data
+import Data.Monoid
+import Control.Arrow
+import Control.Exception
+import Prelude hiding (foldr)
+import Data.Foldable
+
+-- | The result of running a process
+newtype ExitCode =
+  ExitCode Int
+  deriving (Eq, Ord, Data, Typeable)
+
+instance Read ExitCode where
+  readsPrec n s =
+    first exitCode `map` readsPrec n s
+
+instance Show ExitCode where
+  show (ExitCode n) =
+    if n == 0 then "ExitSuccess" else "ExitFailure " ++ show n
+
+instance Exception ExitCode where
+  toException =
+    toException . toExitCode
+  fromException =
+    fmap fromExitCode . fromException
+
+instance Monoid ExitCode where
+  mempty =
+    success
+  a `mappend` b =
+    if isSuccess a then b else a
+
+-- | Construct a process result.
+-- A value of @0@ denotes success, otherwise, failure.
+exitCode ::
+  Int
+  -> ExitCode
+exitCode =
+  ExitCode
+
+-- | Construct a process result with the value @0@.
+success ::
+  ExitCode
+success =
+  exitCode 0
+
+-- | Returns true if the given process result was constructed with the value @0@, otherwise false.
+isSuccess ::
+  ExitCode
+  -> Bool
+isSuccess (ExitCode n) =
+  n == 0
+
+-- | Returns false if the given process result was constructed with the value @0@, otherwise true.
+isFailure ::
+  ExitCode
+  -> Bool
+isFailure =
+  not . isSuccess
+
+-- | Returns the value that the given process result was constructed with.
+exitValue ::
+  ExitCode
+  -> Int
+exitValue (ExitCode n) =
+  n
+
+-- | Computation 'exitWith' @code@ throws 'ExitCode' @code@.
+-- Normally this terminates the program, returning @code@ to the
+-- program's caller.  Before the program terminates, any open or
+-- semi-closed handles are first closed.
+--
+-- A program that fails in any other way is treated as if it had
+-- called 'exitFailure'.
+-- A program that terminates successfully without calling 'exitWith'
+-- explicitly is treated as it it had called 'exitWith' 'ExitSuccess'.
+--
+-- As an 'ExitCode' is not an 'IOError', 'exitWith' bypasses
+-- the error handling in the 'IO' monad and cannot be intercepted by
+-- 'catch' from the "Prelude".  However it is a 'SomeException', and can
+-- be caught using the functions of "Control.Exception".  This means
+-- that cleanup computations added with 'Control.Exception.bracket'
+-- (from "Control.Exception") are also executed properly on 'exitWith'.
+--
+-- Note: in GHC, 'exitWith' should be called from the main program
+-- thread in order to exit the process.  When called from another
+-- thread, 'exitWith' will throw an 'ExitException' as normal, but the
+-- exception will not cause the process itself to exit.
+exitWith ::
+  ExitCode
+  -> IO a
+exitWith =
+  E.exitWith . toExitCode
+
+-- | The computation 'exitFailure' is equivalent to
+-- 'exitWith' @(@'exitCode exitfail'@)@,
+-- where /exitfail/ is implementation-dependent.
+exitFailure ::
+  IO a
+exitFailure =
+  exitWith (exitCode 1)
+
+-- | The computation 'exitSuccess' is equivalent to
+-- 'exitWith' 'success', It terminates the program
+-- sucessfully.
+exitSuccess ::
+  IO a
+exitSuccess =
+  exitWith success
+
+-- | Runs the first action.
+--
+-- Only if the result is successful, run the second action.
+(->>) ::
+  Monad m =>
+  m ExitCode
+  -> m ExitCode
+  -> m ExitCode
+a ->> b =
+  do a' <- a
+     if isSuccess a' then b else return a'
+
+
+-- | Runs the second action.
+--
+-- Only if the result is successful, run the first action.
+(<<-) ::
+  Monad m =>
+  m ExitCode
+  -> m ExitCode
+  -> m ExitCode
+(<<-) =
+  flip (->>)
+
+-- | Run the structure of actions stopping at the first failure.
+runExitCodes ::
+  (Monad m, Foldable f) =>
+  f (m ExitCode)
+  -> m ExitCode
+runExitCodes =
+  foldr (->>) (return success)
+
+-- | readProcessWithExitCode creates an external process, reads its
+-- standard output and standard error strictly, waits until the process
+-- terminates, and then returns the 'ExitCode' of the process,
+-- the standard output, and the standard error.
+--
+-- 'readProcess' and 'readProcessWithExitCode' are fairly simple wrappers
+-- around 'createProcess'.  Constructing variants of these functions is
+-- quite easy: follow the link to the source code to see how
+-- 'readProcess' is implemented.
+readProcessWithExitCode ::
+  FilePath
+  -> [String]
+  -> String
+  -> IO (ExitCode, String, String)
+readProcessWithExitCode p args i =
+  fmap (\(e, t, u) -> (fromExitCode e, t, u)) (P.readProcessWithExitCode p args i)
+
+-- | Computation @system cmd@ returns the exit code produced when the
+-- operating system runs the shell command @cmd@.
+--
+-- This computation may fail with
+--
+--    * @PermissionDenied@: The process has insufficient privileges to
+--      perform the operation.
+--
+--    * @ResourceExhausted@: Insufficient resources are available to
+--      perform the operation.
+--
+--    * @UnsupportedOperation@: The implementation does not support
+--      system calls.
+--
+-- On Windows, 'system' passes the command to the Windows command
+-- interpreter (@CMD.EXE@ or @COMMAND.COM@), hence Unixy shell tricks
+-- will not work.
+system ::
+  String
+  -> IO ExitCode
+system =
+  fmap fromExitCode . P.system
+
+-- | The computation @'rawSystem' cmd args@ runs the operating system command
+-- @cmd@ in such a way that it receives as arguments the @args@ strings
+-- exactly as given, with no funny escaping or shell meta-syntax expansion.
+-- It will therefore behave more portably between operating systems than 'system'.
+--
+-- The return codes and possible failures are the same as for 'system'.
+rawSystem ::
+  String
+  -> [String]
+  -> IO ExitCode
+rawSystem z =
+  fmap fromExitCode . P.rawSystem z
+
+-- | Waits for the specified process to terminate, and returns its exit code.
+
+-- GHC Note: in order to call @waitForProcess@ without blocking all the
+-- other threads in the system, you must compile the program with
+-- @-threaded@.
+waitForProcess ::
+  P.ProcessHandle
+  -> IO ExitCode
+waitForProcess =
+  fmap fromExitCode . P.waitForProcess
+
+
+-- | This is a non-blocking version of 'waitForProcess'.  If the process is
+-- still running, 'Nothing' is returned.  If the process has exited, then
+-- @'Just' e@ is returned where @e@ is the exit code of the process.
+getProcessExitCode ::
+  P.ProcessHandle
+  -> IO (Maybe ExitCode)
+getProcessExitCode =
+  (fmap . fmap) fromExitCode . P.getProcessExitCode
+
+-- not exported
+
+toExitCode ::
+  ExitCode
+  -> E.ExitCode
+toExitCode (ExitCode n) =
+  if n == 0 then E.ExitSuccess else E.ExitFailure n
+
+fromExitCode ::
+  E.ExitCode
+  -> ExitCode
+fromExitCode E.ExitSuccess =
+  success
+fromExitCode (E.ExitFailure n) =
+  exitCode n
