diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -10,13 +10,13 @@
 
 ```bash
 usage:
-task-manager help 
-task-manager -d <task-directory :: [Char]> edit <task-name :: [Char]> 
-task-manager -d <task-directory :: [Char]> open <task-name :: [Char]> 
-task-manager -d <task-directory :: [Char]> close <task-name :: [Char]> 
-task-manager -d <task-directory :: [Char]> tasks 
-task-manager -d <task-directory :: [Char]> priorities 
-task-manager -d <task-directory :: [Char]> 
+task-manager help
+task-manager (required env: TASK_DIRECTORY :: [Char]> edit <task-name :: [Char]>
+task-manager (required env: TASK_DIRECTORY :: [Char]> open <task-name :: [Char]>
+task-manager (required env: TASK_DIRECTORY :: [Char]> close <task-name :: [Char]>
+task-manager (required env: TASK_DIRECTORY :: [Char]> tasks
+task-manager (required env: TASK_DIRECTORY :: [Char]> priorities
+task-manager (required env: TASK_DIRECTORY :: [Char]>
 ```
 
 
diff --git a/Test.hs b/Test.hs
--- a/Test.hs
+++ b/Test.hs
@@ -15,10 +15,11 @@
 import Control.Monad
 import System.Exit
 import Control.Exception
+import System.Environment (setEnv)
 import Data.Maybe
 
 main :: IO ()
-main = rawTest >> argTest >> optTest >> flagTest >> bigProgTests
+main = rawTest >> argTest >> optTest >> flagTest >> bigProgTests >> optDefTest >> envTest
 
 rawProg :: ProgramT Raw IO Bool
 rawProg = raw (pure True)
@@ -74,6 +75,21 @@
 optDefProg prop = optDef "Default" \o -> raw (pure (prop o))
 
 optDefTest :: IO ()
-optDefTest = parlay (== "Default") (State mempty mempty mempty)
-          >> parlay (== "hello") (State mempty (HashMap.fromList [("o", "hello")]) mempty) where
-  parlay prop state = maybe exitFailure (cond (pure ()) exitFailure) =<< runCommanderT (run (optDefProg prop)) state
+optDefTest = 
+     parlay (pure ()) exitFailure (== "Default") (State mempty mempty mempty)
+  >> parlay (pure ()) exitFailure (== "hello") (State mempty (HashMap.fromList [("o", "hello")]) mempty)
+  >> parlay exitFailure (pure ()) (== "Default0") (State mempty mempty mempty)
+  >> parlay exitFailure (pure ()) (== "hello0") (State mempty (HashMap.fromList [("o", "hello")]) mempty)
+  where
+  parlay y n prop state = maybe exitFailure (cond y n) =<< runCommanderT (run (optDefProg prop)) state
+
+envProg :: (x -> Bool) -> ProgramT (Env 'Required "ONOGOTTAFINDABIGNAME" x & Raw) IO Bool
+envProg prop = env \e -> raw (pure (prop e))
+
+envTest :: IO ()
+envTest = do
+  testBool =<< isNothing <$> test (envProg (== ("POOP" :: String))) (State mempty mempty mempty)
+  setEnv "ONOGOTTAFINDABIGNAME" "POOP"
+  testMaybeBool =<< test (envProg (== ("POOP" :: String))) (State mempty mempty mempty)
+  setEnv "ONOGOTTAFINDABIGNAME" "POP"
+  testMaybeBool =<< fmap not <$> test (envProg (== ("POOP" :: String))) (State mempty mempty mempty)
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -13,7 +13,7 @@
 import Options.Commander 
 import Prelude
 import System.Directory
-import System.Process
+import System.Process hiding (env)
 import Data.List
 import Text.Read
 import System.Exit
@@ -22,7 +22,7 @@
 type TaskManager
   = Named "task-manager"
   & ("help" & Raw
-  + Opt "d" "task-directory" FilePath
+  + Env 'Required "TASK_DIRECTORY" FilePath
     & ("edit"  & TaskProgram
      + "open"  & TaskProgram
      + "close" & TaskProgram
@@ -35,7 +35,7 @@
 type TaskProgram = Arg "task-name" String & Raw
   
 taskManager :: ProgramT TaskManager IO ()
-taskManager = toplevel @"task-manager" . optDef @"d" @"task-directory" "tasks" $ \tasksFilePath -> 
+taskManager = toplevel @"task-manager" . env @"TASK_DIRECTORY" $ \tasksFilePath -> 
       sub @"edit" (editTask tasksFilePath) 
   <+> sub @"open" (newTask tasksFilePath)
   <+> sub @"close" (closeTask tasksFilePath)
diff --git a/commander-cli.cabal b/commander-cli.cabal
--- a/commander-cli.cabal
+++ b/commander-cli.cabal
@@ -1,7 +1,7 @@
 cabal-version:       2.4
 
 name:                commander-cli
-version:             0.5.0.0
+version:             0.6.0.0
 synopsis:            A command line argument/option parser library built around a monadic metaphor
 description:         A command line argument/option parser library built around a monadic metaphor.
 homepage:            https://github.com/SamuelSchlesinger/commander-cli
diff --git a/src/Options/Commander.hs b/src/Options/Commander.hs
--- a/src/Options/Commander.hs
+++ b/src/Options/Commander.hs
@@ -54,6 +54,7 @@
 
 @
 usage:
+file help
 file maybe-read \<filename :: String\> ~read
 file maybe-write -file \<file-to-write :: String\>
 @
@@ -74,13 +75,13 @@
   {- |
     To construct a 'ProgramT' (a specification of a CLI program), you can
     have 'arg'uments, 'opt'ions, 'raw' actions in a monad (typically IO),
-    'sub'programs, 'named' programs, you can combine programs together using 
-    '<+>', and you can generate primitive 'usage' information with 'usage'.
-    We also have a convenience combinator, 'toplevel', which lets you add
-    a name and a help command to your program using the 'usage' combinator.
+    'sub'programs, 'named' programs, 'env'ironment variables, you can combine 
+    programs together using '<+>', and you can generate primitive 'usage'
+    information with 'usage'. There are combinators for retrieving environment
+    variables as well. We also have a convenience combinator, 'toplevel',
+    which lets you add a name and a help command to your program using the 'usage' combinator.
   -}
-  arg, opt, optDef, raw, sub, named, flag, toplevel, (<+>), usage,
-  -- ** Describing CLI Programs
+  arg, opt, optDef, raw, sub, named, flag, toplevel, (<+>), usage, env, envOpt, envOptDef,
   -- ** Run CLI Programs
   {- |
     To run a 'ProgramT' (a specification of a CLI program), you will 
@@ -91,7 +92,7 @@
     Each 'ProgramT' has a type level description, build from these type level
     combinators.
   -}
-  type (&), type (+), Arg, Opt, Named, Raw, Flag,
+  type (&), type (+), Arg, Opt, Named, Raw, Flag, Env, Optionality(Required, Optional),
   -- ** Interpreting CLI Programs
   {- |
     The 'HasProgram' class forms the backbone of this library, defining the
@@ -105,6 +106,8 @@
            SubProgramT, unSubProgramT,
            NamedProgramT, unNamedProgramT,
            FlagProgramT, unFlagProgramT,
+           EnvProgramT'Optional, unEnvProgramT'Optional, unEnvDefault,
+           EnvProgramT'Required, unEnvProgramT'Required,
            (:+:)
            ),
   -- ** The CommanderT Monad
@@ -138,7 +141,7 @@
 import GHC.TypeLits (Symbol, KnownSymbol, symbolVal)
 import GHC.Generics (Generic)
 import Numeric.Natural
-import System.Environment (getArgs)
+import System.Environment (getArgs, lookupEnv)
 import Data.Typeable (Typeable, typeRep)
 import qualified Data.ByteString as SBS
 import qualified Data.ByteString.Char8 as BS8
@@ -215,6 +218,10 @@
 instance Unrender Char where
   unrender = find (const True)
 
+-- | The type level naming combinator, giving your program a name for the
+-- sake of documentation.
+data Named :: Symbol -> *
+
 -- | The type level argument combinator, with a 'Symbol' designating the
 -- name of that argument.
 data Arg :: Symbol -> * -> *
@@ -224,23 +231,27 @@
 -- documentation purposes.
 data Opt :: Symbol -> Symbol -> * -> *
 
--- | The type level naming combinator, giving your program a name for the
--- sake of documentation.
-data Named :: Symbol -> *
+-- | The type level flag combinator, taking a name as input, allowing your
+-- program to take flags with the syntax @~flag@.
+data Flag :: Symbol -> *
 
--- | The type level program sequencing combinator, taking two program types
--- and sequencing them one after another.
-data (&) :: k -> * -> *
-infixr 4 &
+-- | The type level environment variable combinator, taking a name as
+-- input, allowing your program to take environment variables as input
+-- automatically.
+data Env :: Optionality -> Symbol -> * -> *
 
 -- | The type level raw monadic program combinator, allowing a command line
 -- program to just do some computation.
 data Raw :: *
 
--- | The type level flag combinator, taking a name as input, allowing your
--- program to take flags with the syntax @~flag@.
-data Flag :: Symbol -> *
+-- | The type level tag for whether or not a variable is required or not.
+data Optionality = Required | Optional
 
+-- | The type level program sequencing combinator, taking two program types
+-- and sequencing them one after another.
+data (&) :: k -> * -> *
+infixr 4 &
+
 -- | The type level combining combinator, taking two program types as
 -- input, and being interpreted as a program which attempts to run the
 -- first command line program and, if parsing its flags, subprograms,
@@ -394,6 +405,41 @@
   hoist :: (forall x. m x -> n x) -> ProgramT p m a -> ProgramT p n a
   invocations :: [Text]
 
+instance (Unrender t, KnownSymbol name, HasProgram p) => HasProgram (Env 'Required name t & p) where
+  newtype ProgramT (Env 'Required name t & p) m a = EnvProgramT'Required { unEnvProgramT'Required :: t -> ProgramT p m a }
+  run f = Action $ \state -> do
+    val <- lookupEnv (symbolVal (Proxy @name))
+    case val of
+      Just v ->
+        case unrender (pack v) of
+          Just t -> return (run (unEnvProgramT'Required f t), state)  
+          Nothing -> return (Defeat, state)
+      Nothing -> return (Defeat, state)
+  hoist n (EnvProgramT'Required f) = EnvProgramT'Required (hoist n . f)
+  invocations =
+    [(("(required env: " <> pack (symbolVal (Proxy @name))
+    <> " :: " <> pack (show (typeRep (Proxy @t)))
+    <> "> ") <>)] <*> invocations @p
+
+instance (Unrender t, KnownSymbol name, HasProgram p) => HasProgram (Env 'Optional name t & p) where
+  data ProgramT (Env 'Optional name t & p) m a = EnvProgramT'Optional
+    { unEnvProgramT'Optional :: Maybe t -> ProgramT p m a
+    , unEnvDefault :: Maybe t }
+  run f = Action $ \state -> do
+    val <- lookupEnv (symbolVal (Proxy @name))
+    case val of
+      Just v ->
+        case unrender (pack v) of
+          Just t -> return (run (unEnvProgramT'Optional f t), state)  
+          Nothing -> return (Defeat, state)
+      Nothing -> return (run (unEnvProgramT'Optional f (unEnvDefault f)), state)
+
+  hoist n (EnvProgramT'Optional f d) = EnvProgramT'Optional (hoist n . f) d
+  invocations =
+    [(("(optional env: " <> pack (symbolVal (Proxy @name))
+    <> " :: " <> pack (show (typeRep (Proxy @t)))
+    <> "> ") <>)] <*> invocations @p
+
 instance (Unrender t, KnownSymbol name, HasProgram p) => HasProgram (Arg name t & p) where
   newtype ProgramT (Arg name t & p) m a = ArgProgramT { unArgProgramT :: t -> ProgramT p m a }
   run f = Action $ \State{..} -> do
@@ -501,6 +547,27 @@
         => ProgramT p IO a 
         -> IO (Maybe a)
 command prog = initialState >>= runCommanderT (run prog)
+
+-- | Required environment variable combinator
+env :: KnownSymbol name
+  => (x -> ProgramT p m a)
+  -> ProgramT (Env 'Required name x & p) m a
+env = EnvProgramT'Required
+
+-- | Optional environment variable combinator
+envOpt :: KnownSymbol name
+  => (Maybe x -> ProgramT p m a)
+  -> ProgramT (Env 'Optional name x & p) m a
+envOpt = flip EnvProgramT'Optional Nothing
+
+-- | Optional environment variable combinator with default
+envOptDef :: KnownSymbol name
+  => x
+  -> (x -> ProgramT p m a)
+  -> ProgramT (Env 'Optional name x & p) m a
+envOptDef x f = EnvProgramT'Optional { unEnvDefault = Just x, unEnvProgramT'Optional = \case { Just x -> f x; Nothing -> error "Violated invariant of optEnvDef" } }
+
+-- | Environment 
 
 -- | Argument combinator
 arg :: KnownSymbol name
