diff --git a/env-parser.cabal b/env-parser.cabal
--- a/env-parser.cabal
+++ b/env-parser.cabal
@@ -1,22 +1,19 @@
 name:                env-parser
-version:             0.0.1.1
+version:             0.0.2
 synopsis:            Pull configuration information from the ENV
 description:         
-  @env-parser@ is a small library for configuring programs based on information
-  from the environment.
-  .
-  Command-line oriented programs tend to pull much of their runtime
-  configuration from command-line arguments and libraries such as @cmdargs@ are
-  useful for encoding this configuration in your program. For programs which
-  draw configuration from the environment, however, this must usually be done
-  manually.
-  .
-  @env-parser@ focuses on making ENV-configured programs both easy to build,
-  declarative, self-documenting, and easy to test.
+
+  @env-parser is a small library for configuring programs based on information
+  from the environment. It's goals and design are similar to that of @cmdargs@
+  or @optparse-applicative@ but aimed at automatically managed programs such as
+  those that might be run via Heroku or Runit/daemontools.
   .
-  A particular use case of this parser is to make it easy to build applications
-  which launch under Heroku-style infrastructure. We provide explicit parsers
-  for some of Heroku's conventions for this purpose.
+  @env-parser@ intentionally sacrifices power for comprehensibility---the
+  primary interface, @Parser@, implements only @Applicative@. This provides
+  better runtime error messages and automatically generated static help using
+  parser annotations. It also expresses a principle of simplicity in
+  configuration: arbitrary uses of @Monad@ or even @Alternative@ can lead to
+  opaque failures prior to a program even beginning to run.
 
 homepage:            http://github.com/tel/env-parser
 license:             MIT
diff --git a/src/System/Environment/Parser.hs b/src/System/Environment/Parser.hs
--- a/src/System/Environment/Parser.hs
+++ b/src/System/Environment/Parser.hs
@@ -12,25 +12,64 @@
 -- Portability : non-portable
 --
 -- Functions for building generic environment parsers which provide
--- automatic documentation and easy testing.
+-- automatic documentation and easy testing. 
 --
+-- This module is intended to be imported qualified, for example, we might
+-- parse out a Heroku database URL and a base-64 encoded encryption key in
+-- the following manner.
+--
+-- > import qualified System.Environment.Parser          as Env
+-- > import qualified System.Environment.Parser.Database as Env
+-- > import qualified System.Environment.Parser.Encoded  as Env
+-- >
+-- > data Config = Config { db :: Env.DBConnection, key :: Env.Base64 }
+-- > 
+-- > configP :: Parser Config
+-- > configP = Config <$> Env.get "DATABASE_URL"
+-- >                  <*> Env.get "ENCRYPTION_KEY"
+--
+-- We can then use that 'Parser' value to attempt to compute a @Config@ in
+-- 'IO' and print out the missing and needed variables on failure
+--
+-- > do cp <- Env.run configP :: IO (Either Errors Config)
+-- >    case cp of
+-- >      Left errs   -> do
+-- >        putStrLn "Missing the following variables: "
+-- >        mapM_ putStrLn (Env.missing errs)
+-- >        putStrLn "Needs the following variables: "
+-- >        mapM_ putStrLn (Env.references (Env.analyze configP))
+-- >      Right config -> do
+-- >        ...
+--
 module System.Environment.Parser (
 
   -- * Basic interface
 
-    run       -- :: Parser a -> IO (Either Errors a)
-  , test      -- :: Parser a -> Map.Map String String -> Either Errors a
-  , help      -- :: Parser a -> Dep
+  -- ** Building a ''Parser'
+
+  Parser
+  
   , get       -- :: FromEnv a  => String -> Parser a
   , getParse  -- :: FE.FromEnv a => (a -> Either String b) -> String -> Parser b
   , json      -- :: FromJSON a => String -> Parser a
 
-  -- * Interface types
+  -- *** Annotating a 'Parser'
+  , def       -- :: Show a => a -> Parser a -> Parser a
+  , def'      -- ::           a -> Parser a -> Parser a
+  , doc       -- :: String -> Parser a -> Parser a
 
-  , Parser
-  , Errors (..), Err (..)
-  , Dep    (..), references
+  -- * Interpreting a 'Parser'
+    
+  , run       -- :: Parser a -> IO (Either Errors a)
+  , test      -- :: Parser a -> Map.Map String String -> Either Errors a
+  , analyze   -- :: Parser a -> Analysis
 
+  , Errors (..), missing
+  , Err (..)
+
+  -- ** Analysis and documentation
+  , Analysis (..), references
+
   ) where
 
 import           Control.Applicative
@@ -38,6 +77,7 @@
 import qualified Data.Aeson.Types                  as Ae
 import           Data.Functor.Compose
 import qualified Data.Map                          as Map
+import           Data.Maybe                        (mapMaybe)
 import           Data.Monoid
 import           Data.Foldable                     (toList, foldMap)
 import           Data.Sequence                     ((<|), (|>))
@@ -49,12 +89,23 @@
 -- -----------------------------------------------------------------------------
 -- Error types
 
+-- | We consider two broad classes of failure: either an environment
+-- variable was expected to exist and didn't (it was 'Wanted') or the
+-- value failed to validate during parsing and we've 'Joined' an
+-- error message from that failed parse.
 data Err = Wanted String | Joined String
   deriving ( Eq, Ord, Show )
 
 newtype Errors = Errors { getErrors :: Seq.Seq Err }
   deriving ( Eq, Ord, Show, Monoid )
 
+-- | Determine all of the variables which were missing in the environment
+-- yet required.
+missing :: Errors -> [String]
+missing = mapMaybe go . toList . getErrors where
+  go (Wanted s) = Just s
+  go (Joined _) = Nothing
+
 instance Cls.Satisfiable Errors where
   wants  = Errors . Seq.singleton . Wanted
   errors = Errors . Seq.singleton . Joined
@@ -62,22 +113,31 @@
 -- -----------------------------------------------------------------------------
 -- Analysis types
 
-data Dep = Succeeding
-         | Needing    String
-         | Branching  (Seq.Seq Dep)
-         | Joining    Dep
-         | Defaulting String Dep
+-- | The 'Analysis' type is a result of running the parser
+-- statically. It provides some information about the kind of parse
+-- that would be attempted and is thus useful for error messages or
+-- manual documentation.
+data Analysis
+  = Succeeding
+  | Wanting     String
+  | Branching   (Seq.Seq Analysis)
+  | Joining     Analysis
+  | Defaulting  String Analysis
+  | Documenting String Analysis
   deriving ( Eq, Show )
 
-references :: Dep -> [String]
-references = toList . foldDep where
-  foldDep Succeeding       = Seq.empty
-  foldDep (Needing key)    = Seq.singleton key
-  foldDep (Branching ds)   = foldMap foldDep ds
-  foldDep (Joining d)      = foldDep d
-  foldDep (Defaulting _ d) = foldDep d
+-- | Get each environment varaible the parser wants. This will include
+-- ones that may be optional due to default values.
+references :: Analysis -> [String]
+references = toList . foldAnalysis where
+  foldAnalysis Succeeding          = Seq.empty
+  foldAnalysis (Wanting key)       = Seq.singleton key
+  foldAnalysis (Branching ds)      = foldMap foldAnalysis ds
+  foldAnalysis (Joining d)         = foldAnalysis d
+  foldAnalysis (Defaulting _ d)    = foldAnalysis d
+  foldAnalysis (Documenting doc d) = foldAnalysis d
 
-data Df a = Df { runDf :: Dep } deriving Functor
+data Df a = Df { runDf :: Analysis } deriving Functor
 
 instance Applicative Df where
   pure _ = Df Succeeding
@@ -87,7 +147,7 @@
   Df df              <*> Df dx              = Df (Branching $ Seq.fromList [df, dx])
 
 instance Cls.HasEnv Df where
-  getEnv key = Df (Needing key)
+  getEnv key = Df (Wanting key)
 
 instance Cls.Env Df where
   joinFailure (Df dep)   = Df (Joining dep)
@@ -96,10 +156,15 @@
 -- -----------------------------------------------------------------------------
 -- Parser types
 
+-- | The generic environment 'Parser'. This type is used to specify
+-- the structure of a configuration which can be read from the
+-- environment. Later that structure can either be examined using
+-- 'analyze', tested using 'test', or performed on the actual
+-- environment using 'run'.
 data Parser a = Parser
-  { run'  :: Compose IO (Miss Errors) a
-  , test' :: Compose ((->) (Map.Map String String)) (Miss Errors) a
-  , help' :: Df a
+  { run'     :: Compose IO (Miss Errors) a
+  , test'    :: Compose ((->) (Map.Map String String)) (Miss Errors) a
+  , analyze' :: Df a
   }
   deriving ( Functor )
 
@@ -117,20 +182,48 @@
   def a sho   (Parser i1 i2 i3) =
     Parser (Cls.def a sho i1) (Cls.def a sho i2) (Cls.def a sho i3)
 
+-- | Run a 'Parser' in 'IO' using the actual environment.
 run :: Parser a -> IO (Either Errors a)
 run = fmap toEither . getCompose . run'
 
+-- | Run a 'Parser' purely using a 'Map.Map' to simulate the
+-- environment.
 test :: Parser a -> Map.Map String String -> Either Errors a
 test = fmap toEither . getCompose . test'
 
-help :: Parser a -> Dep
-help = runDf . help'
+-- | Run a completely pure, static analysis of the 'Parser' that can
+-- be used to generate helpful documentation.
+analyze :: Parser a -> Analysis
+analyze = runDf . analyze'
 
+-- | Pull a value from the environment.
 get :: FE.FromEnv a => String -> Parser a
 get = FE.fromEnv . Cls.getEnv
 
+-- | Assign a default value to a 'Parser'. If the parser should fail at
+-- runtime the default value will be returned instead. The value must
+-- be showable in order to provide documentation.
+def :: Show a => a -> Parser a -> Parser a
+def a = Cls.def a show
+
+-- | Assign a default value to a 'Parser'. This is identical to 'def'
+-- but does not require the default value has a 'Show'
+-- instance---instead a constant descriptive string should be passed
+-- directly.
+def' :: a -> String -> Parser a -> Parser a
+def' a str = Cls.def a (const $ "{" ++ str ++ "}")
+
+-- | Assign documentation to a branch of the 'Parser'. This can be
+-- later retrieved in the 'Analysis' type.
+doc :: String -> Parser a -> Parser a
+doc = Cls.doc
+
+-- | Pull a string from the environment and interpret it as a
+-- JSON-serializable type.
 json :: Ae.FromJSON a => String -> Parser a
 json = getParse (Ae.parseEither Ae.parseJSON)
 
+-- | Pull a value from the environment and attempt to parse it into
+-- some other type. Failures will be 'Joined' into the result.
 getParse :: FE.FromEnv a => (a -> Either String b) -> String -> Parser b
 getParse parse key = Cls.joinFailure $ fmap parse $ get key
diff --git a/src/System/Environment/Parser/Class.hs b/src/System/Environment/Parser/Class.hs
--- a/src/System/Environment/Parser/Class.hs
+++ b/src/System/Environment/Parser/Class.hs
@@ -60,11 +60,15 @@
   -- | Replace a result with a default if necessary
   def :: a -> (a -> String) -> r a -> r a
 
+  -- | Provide documentation on a particular value
+  doc :: String -> r a -> r a
+  doc = flip const
+
 instance Satisfiable e => HasEnv (Miss e) where
   getEnv key = Miss (wants key)
 
 instance Satisfiable e => Env (Miss e) where
-  joinFailure (Miss er) = Miss er
+  joinFailure (Miss er)       = Miss er
   joinFailure (Got (Left er)) = Miss (errors er)
   joinFailure (Got (Right a)) = Got a
 
diff --git a/src/System/Environment/Parser/Database.hs b/src/System/Environment/Parser/Database.hs
--- a/src/System/Environment/Parser/Database.hs
+++ b/src/System/Environment/Parser/Database.hs
@@ -38,6 +38,7 @@
               | AMQP     S.ByteString
               | HTTP     S.ByteString
               | Other    S.ByteString
+  deriving ( Eq, Ord, Show, Read )
 
 providerString :: Provider -> S.ByteString
 providerString p = case p of
@@ -70,6 +71,7 @@
   , location :: S.ByteString
   , params   :: Map.Map S.ByteString S.ByteString
   }
+  deriving ( Eq, Ord, Show, Read )
 
 instance FromEnv DBConnection where
   parseEnv = tryParse
