diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+## 0.4.1
+
+* Cli improvements: UI tweaks and --recursive flag [#28](https://github.com/snoyberg/packdeps/pull/28)
diff --git a/Distribution/PackDeps.hs b/Distribution/PackDeps.hs
--- a/Distribution/PackDeps.hs
+++ b/Distribution/PackDeps.hs
@@ -9,6 +9,7 @@
     , parseNewest
       -- * Check a package
     , checkDeps
+    , checkLibDeps
       -- * Get a single package
     , getPackage
     , parsePackage
@@ -16,6 +17,7 @@
       -- * Get multiple packages
     , filterPackages
     , deepDeps
+    , deepLibDeps
       -- * Reverse dependencies
     , Reverses
     , getReverses
@@ -161,6 +163,7 @@
 data DescInfo = DescInfo
     { diHaystack :: String
     , diDeps :: [Dependency]
+    , diLibDeps :: [Dependency]
     , diPackage :: PackageIdentifier
     , diSynopsis :: String
     }
@@ -170,6 +173,7 @@
 getDescInfo gpd = DescInfo
     { diHaystack = map toLower $ author p ++ maintainer p ++ name
     , diDeps = getDeps gpd
+    , diLibDeps = getLibDeps gpd
     , diPackage = pi'
     , diSynopsis = synopsis p
     }
@@ -178,14 +182,27 @@
     pi'@(PackageIdentifier (PackageName name) _) = package p
 
 getDeps :: GenericPackageDescription -> [Dependency]
-getDeps x = concat
-          $ maybe id ((:) . condTreeConstraints) (condLibrary x)
-          $ map (condTreeConstraints . snd) (condExecutables x)
+getDeps x = getLibDeps x ++ concat
+    [ concatMap (condTreeConstraints . snd) (condExecutables x)
+    , concatMap (condTreeConstraints . snd) (condTestSuites x)
+    , concatMap (condTreeConstraints . snd) (condBenchmarks x)
+    ]
 
+getLibDeps :: GenericPackageDescription -> [Dependency]
+getLibDeps gpd = maybe [] condTreeConstraints (condLibrary gpd)
+
 checkDeps :: Newest -> DescInfo
           -> (PackageName, Version, CheckDepsRes)
-checkDeps newest desc =
-    case mapMaybe (notNewest newest) $ diDeps desc of
+checkDeps = checkDepsImpl diDeps
+
+checkLibDeps :: Newest -> DescInfo
+             -> (PackageName, Version, CheckDepsRes)
+checkLibDeps = checkDepsImpl diLibDeps
+
+checkDepsImpl :: (DescInfo -> [Dependency]) -> Newest -> DescInfo
+              -> (PackageName, Version, CheckDepsRes)
+checkDepsImpl deps newest desc =
+    case mapMaybe (notNewest newest) $ deps desc of
         [] -> (name, version, AllNewest)
         x -> let y = map head $ group $ sort $ map fst x
                  et = maximum $ map snd x
@@ -245,7 +262,14 @@
 
 -- | Find all packages depended upon by the given list of packages.
 deepDeps :: Newest -> [DescInfo] -> [DescInfo]
-deepDeps newest dis0 =
+deepDeps = deepDepsImpl diDeps
+
+-- | Find all packages depended upon by the given list of packages.
+deepLibDeps :: Newest -> [DescInfo] -> [DescInfo]
+deepLibDeps = deepDepsImpl diLibDeps
+
+deepDepsImpl :: (DescInfo -> [Dependency]) -> Newest -> [DescInfo] -> [DescInfo]
+deepDepsImpl deps newest dis0 =
     go Set.empty dis0
   where
     go _ [] = []
@@ -255,7 +279,7 @@
       where
         PackageIdentifier (PackageName name) _ = diPackage di
         viewed' = Set.insert name viewed
-        newDis = mapMaybe getDI $ diDeps di
+        newDis = mapMaybe getDI $ deps di
         getDI :: Dependency -> Maybe DescInfo
         getDI (Dependency (PackageName name') _) = do
             pi' <- Map.lookup name' newest
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+## packdeps
+
+[![Build Status](https://travis-ci.org/snoyberg/packdeps.svg?branch=cli)](https://travis-ci.org/snoyberg/packdeps)
+
+Check the upper bounds on a package to determine if there are newer versions of
+dependencies.
diff --git a/packdeps.cabal b/packdeps.cabal
--- a/packdeps.cabal
+++ b/packdeps.cabal
@@ -1,5 +1,5 @@
 name:            packdeps
-version:         0.4.0.3
+version:         0.4.1
 license:         BSD3
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -14,6 +14,7 @@
 cabal-version:   >= 1.8
 build-type:      Simple
 homepage:        http://packdeps.haskellers.com/
+extra-source-files: README.md ChangeLog.md
 
 library
     build-depends:   base                      >= 4        && < 5
diff --git a/tools/packdeps-cli.hs b/tools/packdeps-cli.hs
--- a/tools/packdeps-cli.hs
+++ b/tools/packdeps-cli.hs
@@ -4,6 +4,8 @@
 import System.Exit (exitFailure, exitSuccess)
 import Distribution.Text (display)
 import Distribution.Package (PackageName (PackageName))
+import Distribution.Version (Version)
+import Control.Monad (liftM)
 
 main :: IO ()
 main = do
@@ -11,41 +13,53 @@
     case args of
         [] -> usageExit
         ["help"] -> usageExit
+        _ | "-h" `elem` args || "--help" `elem` args -> usageExit
         _ -> do
-            isGood <- run args
+            isGood <- run ("--recursive" `elem` args) (filter (/= "--recursive") args)
             if isGood then exitSuccess else exitFailure
 
-run :: [String] -> IO Bool
-run args = do
+type CheckDeps = Newest -> DescInfo -> (PackageName, Version, CheckDepsRes)
+
+checkDepsCli :: CheckDeps -> Newest -> DescInfo -> IO Bool
+checkDepsCli cd newest di =
+    case cd newest di of
+        (pn, v, AllNewest) -> do
+            putStrLn $ concat
+                [ unPackageName pn
+                , "-"
+                , display v
+                , ": Can use newest versions of all dependencies"
+                ]
+            return True
+        (pn, v, WontAccept p _) -> do
+            putStrLn $ concat
+                [ unPackageName pn
+                , "-"
+                , display v
+                , ": Cannot accept the following packages"
+                ]
+            forM_ p $ \(x, y) -> putStrLn $ x ++ " " ++ y
+            return False
+
+run :: Bool        -- ^ Check transitive dependencies
+    -> [FilePath]  -- ^ .cabal filenames
+    -> IO Bool
+run deep args = do
     newest <- loadNewest
     foldM (go newest) True args
   where
     go newest wasAllGood fp = do
         mdi <- loadPackage fp
-        di <-
-            case mdi of
-                Just di -> return di
-                Nothing -> error $ "Could not parse cabal file: " ++ fp
-        allGood <- case checkDeps newest di of
-            (pn, v, AllNewest) -> do
-                putStrLn $ concat
-                    [ unPackageName pn
-                    , "-"
-                    , display v
-                    , ": Can use newest versions of all dependencies"
-                    ]
-                return True
-            (pn, v, WontAccept p _) -> do
-                putStrLn $ concat
-                    [ unPackageName pn
-                    , "-"
-                    , display v
-                    , ": Cannot accept the following packages"
-                    ]
-                forM_ p $ \(x, y) -> putStrLn $ x ++ " " ++ y
-                return False
+        di <- case mdi of
+             Just di -> return di
+             Nothing -> error $ "Could not parse cabal file: " ++ fp
+        allGood <- checkDepsCli checkDeps newest di
+        depsGood <- if deep
+                       then do putStrLn $ "\nTransitive dependencies:"
+                               allM (checkDepsCli checkLibDeps newest) (deepLibDeps newest [di])
+                       else return True
         putStrLn ""
-        return $ wasAllGood && allGood
+        return $ wasAllGood && allGood && depsGood
 
 unPackageName :: PackageName -> String
 unPackageName (PackageName n) = n
@@ -55,8 +69,13 @@
 usageExit = do
     pname <- getProgName
     putStrLn $ "\n"
-        ++ "Usage: " ++ pname ++ " pkgname.cabal\n\n"
+        ++ "Usage: " ++ pname ++ " [--recursive] pkgname.cabal pkgname2.cabal...\n\n"
         ++ "Check the given cabal file's dependency list to make sure that it does not exclude\n"
         ++ "the newest package available. Its probably worth running the 'cabal update' command\n"
         ++ "immediately before running this program.\n"
     exitSuccess
+
+-- | Non short-circuiting monadic version of 'all'
+-- Duh, pre-AMP code.
+allM :: Monad m => (a -> m Bool) -> [a] -> m Bool
+allM f xs = and `liftM` mapM f xs
