diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -1,6 +1,321 @@
 module Main where
 
-import Web.Tweet.Exec
+import qualified Data.ByteString.Lazy.Char8 as BSL
+import           Data.Maybe
+import           Data.Version
+import           Options.Applicative
+import           Paths_tweet_hs
+import           System.Directory
+import           Web.Tweet
 
+-- | Data type for our program: one optional path to a credential file, (optionally) the number of tweetInputs to make, the id of the status you're replying to, and a list of users you wish to mention.
+data Program = Program { subcommand :: Command , cred :: Maybe FilePath , color :: Bool }
+
+-- | Data type for a command
+-- TODO add boolean option to show ids alongside tweets
+data Command = Timeline { count :: Maybe Int }
+    | SendInput { tweetInputs :: Maybe Int, replyId :: Maybe String, replyh :: Maybe [String] }
+    | Profile { count :: Maybe Int , screenName'' :: Maybe String, withReplies :: Bool, withRetweets :: Bool }
+    | Mentions { count :: Maybe Int }
+    | Markov { screenName' :: String }
+    | Send { tweets :: Maybe Int , replyId :: Maybe String , replyh :: Maybe [String] , userInput :: String }
+    | Sort { screenName' :: String , count :: Maybe Int , includeReplies :: Bool }
+    | Delete { twId :: Integer }
+    | Fav { twId :: Integer }
+    | Unfav { twId :: Integer }
+    | Retweet { twId :: Integer }
+    | Unretweet { twId :: Integer }
+    | List { count :: Maybe Int , screenName' :: String }
+    | Follow { screenName' :: String }
+    | Unfollow { screenName' :: String }
+    | Block { screenName' :: String }
+    | Unblock { screenName' :: String }
+    | Mute { screenName' :: String }
+    | Unmute { screenName' :: String }
+    | Dump { screenName' :: String }
+
+-- | query twitter to post stdin with no fancy options
+fromStdIn :: Int -> FilePath -> IO ()
+fromStdIn = threadStdIn [] Nothing
+
+-- | Tweet string given to us, as parsed from the command line
+fromCLI :: String -> Int -> FilePath -> IO ()
+fromCLI s = thread s [] Nothing
+
+-- | Threaded tweetInputs from stdIn
+threadStdIn :: [String] -> Maybe Int -> Int -> FilePath -> IO ()
+threadStdIn hs idNum num filepath = do
+    contents <- getContents
+    thread contents hs idNum num filepath
+
+-- | Executes parser
 main :: IO ()
-main = exec
+main = putStrLn bird >> execParser opts >>= select
+    where
+        versionInfo = infoOption ("tweet-hs version: " ++ showVersion version) (short 'v' <> long "version" <> help "Show version")
+        opts        = info (helper <*> versionInfo <*> program)
+            (fullDesc
+            <> progDesc "Tweet and view tweets"
+            <> header "clit - a Command Line Interface Tweeter")
+
+-- | Executes program given parsed `Program`
+select :: Program -> IO ()
+select (Program com maybeFile c) = case maybeFile of
+    (Just file) -> selectCommand com (not c) file
+    _ -> selectCommand com (not c) =<< (++ "/.cred.toml") <$> getHomeDirectory
+
+-- | Executes subcommand given subcommand + filepath to configuration file
+selectCommand :: Command -> Bool -> FilePath -> IO ()
+selectCommand (Send maybeNum Nothing Nothing input) _ file = fromCLI input (fromMaybe 15 maybeNum) file
+selectCommand (Send maybeNum (Just rId) Nothing input) _ file = thread input [] (pure . read $ rId) (fromMaybe 15 maybeNum) file
+selectCommand (Send maybeNum Nothing (Just h) input) _ file = thread input h Nothing (fromMaybe 15 maybeNum) file
+selectCommand (Send maybeNum (Just rId) (Just h) input) _ file = thread input h (pure . read $ rId) (fromMaybe 15 maybeNum) file
+selectCommand (SendInput maybeNum Nothing Nothing) _ file  = fromStdIn (fromMaybe 15 maybeNum) file
+selectCommand (SendInput maybeNum (Just rId) (Just h)) _ file = threadStdIn h (pure . read $ rId) (fromMaybe 15 maybeNum) file
+selectCommand (SendInput maybeNum (Just rId) Nothing) _ file = threadStdIn [] (pure . read $ rId) (fromMaybe 15 maybeNum) file
+selectCommand (SendInput maybeNum Nothing (Just h)) _ file = threadStdIn h Nothing (fromMaybe 15 maybeNum) file
+selectCommand (Timeline maybeNum) c file = putStrLn =<< showTimeline (fromMaybe 11 maybeNum) c file
+selectCommand (Mentions maybeNum) c file = putStrLn =<< showTweets c <$> mentions (fromMaybe 11 maybeNum) file
+selectCommand (Profile maybeNum n False False) c file = putStrLn =<< showProfile (fromMaybe mempty n) (fromMaybe 11 maybeNum) c file
+selectCommand (Profile maybeNum n True False) c file = putStrLn =<< showFilteredTL [filterReplies] (fromMaybe mempty n) (fromMaybe 11 maybeNum) c file
+selectCommand (Profile maybeNum n False True) c file = putStrLn =<< showFilteredTL [filterRTs] (fromMaybe mempty n) (fromMaybe 11 maybeNum) c file
+selectCommand (Profile maybeNum n True True) c file = putStrLn =<< showFilteredTL [filterReplies, filterRTs] (fromMaybe mempty n) (fromMaybe 11 maybeNum) c file
+selectCommand (Sort n maybeNum False) c file = putStrLn =<< showBest' n (fromMaybe 11 maybeNum) c file
+selectCommand (Sort n maybeNum True) c file = putStrLn =<< showBest n (fromMaybe 11 maybeNum) c file
+selectCommand (List maybeNum n) c file = putStrLn =<< showFavorites (fromMaybe 11 maybeNum) n c file
+selectCommand (Markov n) _ file = do
+    raw <- getMarkov n Nothing file
+    appendFile (n ++ ".txt") (unlines raw)
+    putStrLn $ "Written output to: " ++ n ++ ".txt"
+selectCommand (Delete n) c file = do
+    putStrLn "Deleted:\n"
+    putStrLn =<< showTweets c <$> deleteTweetResponse n file
+selectCommand (Fav n) c file = do
+    putStrLn "Favorited:\n"
+    putStrLn =<< showTweets c <$> favoriteTweetResponse n file
+selectCommand (Unfav n) c file = do
+    putStrLn "Unfavorited:\n"
+    putStrLn =<< showTweets c <$> unfavoriteTweetResponse n file
+selectCommand (Retweet n) c file = do
+    putStrLn "Retweeted:\n"
+    putStrLn =<< showTweets c <$> retweetTweetResponse n file
+selectCommand (Unretweet n) c file = do
+    putStrLn "Unretweeted:\n"
+    putStrLn =<< showTweets c <$> unretweetTweetResponse n file
+selectCommand (Follow sn) _ file = do
+    follow sn file
+    putStrLn ("..." ++ sn ++ " followed successfully!")
+selectCommand (Unfollow sn) _ file = do
+    unfollow sn file
+    putStrLn ("..." ++ sn ++ " unfollowed successfully!")
+selectCommand (Block sn) _ file = do
+    block sn file
+    putStrLn ("..." ++ sn ++ " blocked successfully")
+selectCommand (Unblock sn) _ file = do
+    unblock sn file
+    putStrLn ("..." ++ sn ++ " unblocked successfully")
+selectCommand (Mute sn) _ file = do
+    mute sn file
+    putStrLn ("..." ++ sn ++ " muted successfully")
+selectCommand (Unmute sn) _ file = do
+    unmute sn file
+    putStrLn ("..." ++ sn ++ " unmuted successfully")
+selectCommand (Dump sn) _ file = BSL.putStrLn =<< getProfileRaw sn 3200 file Nothing
+
+-- | Parser to return a program datatype
+program :: Parser Program
+program = Program
+    <$> hsubparser
+        (command "send" (info tweet (progDesc "Send a tweet from the command-line"))
+        <> command "input" (info tweetInput (progDesc "Send a tweet from stdIn"))
+        <> command "view" (info timeline (progDesc "Get your timeline"))
+        <> command "user" (info profile (progDesc "Get a user's profile"))
+        <> command "markov" (info markov (progDesc "Grab tweets en masse."))
+        <> command "hits" (info best (progDesc "View a user's top tweets."))
+        <> command "del" (info delete (progDesc "Delete a tweet.")) -- TODO delete/favorite in bunches!
+        <> command "fav" (info fav (progDesc "Favorite a tweet"))
+        <> command "ufav" (info unfav (progDesc "Unfavorite a tweet"))
+        <> command "urt" (info unrt (progDesc "Un-retweet a tweet"))
+        <> command "rt" (info rt (progDesc "Retweet a tweet"))
+        <> command "follow" (info fol (progDesc "Follow a user"))
+        <> command "unfollow" (info unfol (progDesc "Unfollow a user"))
+        <> command "list" (info list (progDesc "List a user's favorites"))
+        <> command "dump" (info dump (progDesc "Dump tweets (for debugging)"))
+        <> command "block" (info blockParser (progDesc "Block a user"))
+        <> command "unblock" (info unblockParser (progDesc "Unblock a user"))
+        <> command "mute" (info muteParser (progDesc "Mute a user"))
+        <> command "unmute" (info unmuteParser (progDesc "Unmute a user"))
+        <> command "mentions" (info mentionsParser (progDesc "Fetch mentions")))
+    <*> optional (strOption
+        (long "cred"
+        <> short 'c'
+        <> metavar "CREDENTIALS"
+        <> completer (bashCompleter "file -X '!*.toml' -o plusdirs")
+        <> help "path to credentials"))
+    <*> switch
+        (long "color"
+        <> short 'l'
+        <> help "Turn off colorized terminal output.")
+
+-- | Parser for the view subcommand
+timeline :: Parser Command
+timeline = Timeline
+    <$> optional (read <$> strOption
+        (long "count"
+        <> short 'n'
+        <> metavar "NUM"
+        <> help "number of tweetInputs to fetch, default 5"))
+
+-- | Parser for the markov subcommand
+markov :: Parser Command
+markov = Markov <$> user
+
+-- | Parser for the follow subcommand
+fol :: Parser Command
+fol = Follow <$> user
+
+-- | Parser for the block subcommand
+blockParser :: Parser Command
+blockParser = Block <$> user
+
+-- | Parser for the unblock subcommand
+unblockParser :: Parser Command
+unblockParser = Unblock <$> user
+
+-- | Parser for the dump subcommand
+dump :: Parser Command
+dump = Dump <$> user
+
+-- | Parser for the unfollow subcommand
+unfol :: Parser Command
+unfol = Unfollow <$> user
+
+-- | Parser for the list subcommand
+list :: Parser Command
+list = List
+    <$> optional (read <$> strOption
+        (long "count"
+        <> short 'n'
+        <> metavar "NUM"
+        <> help "Number of tweetInputs to fetch, default 12"))
+    <*> user
+
+-- | Parser for the unfollow subcommand
+muteParser :: Parser Command
+muteParser = Mute <$> user
+
+-- | Parser for the unfollow subcommand
+unmuteParser :: Parser Command
+unmuteParser = Unmute <$> user
+
+-- | Parse a user screen name
+user :: Parser String
+user = argument str
+    (metavar "SCREEN_NAME"
+    <> help "Screen name of user.")
+
+-- | Parser for the del subcommand
+delete :: Parser Command
+delete = Delete <$> getInt
+
+-- | Parser for the fav subcommand
+fav :: Parser Command
+fav = Fav <$> getInt
+
+-- | Parser for the fav subcommand
+unfav :: Parser Command
+unfav = Unfav <$> getInt
+
+-- | Parser for the fav subcommand
+unrt :: Parser Command
+unrt = Unretweet <$> getInt
+
+-- | Parser for the fav subcommand
+rt :: Parser Command
+rt = Retweet <$> getInt
+
+-- | Parser for the del subcommand
+getInt :: Parser Integer
+getInt = read <$> argument str
+    (metavar "TWEET_ID"
+    <> help "ID of tweet")
+
+-- | Parser for the user subcommand
+profile :: Parser Command
+profile = Profile
+    <$> optional (read <$> strOption
+        (long "count"
+        <> short 'n'
+        <> metavar "NUM"
+        <> help "Number of tweetInputs to fetch, default 12"))
+    <*> optional user
+    <*> switch (
+           long "no-replies"
+        <> short 'r'
+        <> help "Don't display replies.")
+    <*> switch (
+           long "no-retweets"
+        <> short 't'
+        <> help "Don't display retweets.")
+
+-- | Parser for the mention subcommand
+mentionsParser :: Parser Command
+mentionsParser = Mentions
+    <$> optional (read <$> strOption
+        (long "count"
+        <> short 'n'
+        <> metavar "NUM"
+        <> help "Number of tweetInputs to fetch, default 12"))
+
+-- | Parse best tweets
+best :: Parser Command
+best = Sort
+    <$> argument str
+        (metavar "SCREEN_NAME"
+        <> help "Screen name of user you want to view.")
+    <*> optional (read <$> strOption
+        (long "count"
+        <> short 'n'
+        <> metavar "NUM"
+        <> help "Number of tweetInputs to fetch, default 12"))
+    <*> switch
+        (long "replies"
+        <> short 'r'
+        <> help "Include replies in your all-time hits")
+
+-- | Parser for the send subcommand
+tweet :: Parser Command
+tweet = Send
+    <$> optional (read <$> strOption
+        (long "tweets"
+        <> short 't'
+        <> metavar "NUM"
+        <> help "Number of tweetInputs in a row, default 15"))
+    <*> optional (strOption
+        (long "reply"
+        <> short 'r'
+        <> help "id of status to reply to - be sure to include their handle, e.g. @my_build_errors"))
+    <*> optional (some $ strOption
+        (long "handle"
+        <> short 'h'
+        <> metavar "HANDLE1"
+        <> help "h to include in replies"))
+    <*> (unwords <$> some (argument str
+        (metavar "TEXT"
+        <> help "text of tweet to be sent")))
+
+-- | Parser for the input command
+tweetInput :: Parser Command
+tweetInput = SendInput
+    <$> optional (read <$> strOption
+        (long "tweets"
+        <> short 't'
+        <> metavar "NUM"
+        <> help "Number of tweets in a row, default 15"))
+    <*> optional (strOption
+        (long "reply"
+        <> short 'r'
+        <> help "id of status to reply to - be sure to include their handle, e.g. @my_build_errors"))
+    <*> optional (some $ argument str
+        (metavar "HANDLE1"
+        <> help "h to include in replies"))
diff --git a/cabal.project.local b/cabal.project.local
--- a/cabal.project.local
+++ b/cabal.project.local
@@ -1,5 +1,5 @@
-with-compiler: ghc-8.2.2
+constraints: tweet-hs +development
 optimization: 2
+tests: True
+benchmarks: True
 documentation: True
-haddock-hoogle: True
-haddock-internal: True
diff --git a/src/Web/Tweet.hs b/src/Web/Tweet.hs
--- a/src/Web/Tweet.hs
+++ b/src/Web/Tweet.hs
@@ -39,11 +39,11 @@
     , bird
     ) where
 
-import           Control.Lens
 import           Control.Monad
 import           Data.Default
 import           Data.List.Split        (chunksOf)
 import           Data.Maybe
+import           Lens.Micro
 import           Web.Tweet.API
 import           Web.Tweet.API.Internal
 import           Web.Tweet.Sign
diff --git a/src/Web/Tweet/API.hs b/src/Web/Tweet/API.hs
--- a/src/Web/Tweet/API.hs
+++ b/src/Web/Tweet/API.hs
@@ -4,11 +4,12 @@
 module Web.Tweet.API where
 
 import           Control.Composition
-import           Control.Lens
 import           Control.Monad
 import qualified Data.ByteString.Lazy.Char8 as BSL
 import           Data.Maybe                 (isJust)
 import           Data.Void
+import           Lens.Micro
+import           Lens.Micro.Extras
 import           Text.Megaparsec.Error
 import           Web.Tweet.Types
 import           Web.Tweet.Utils
diff --git a/src/Web/Tweet/Exec.hs b/src/Web/Tweet/Exec.hs
deleted file mode 100644
--- a/src/Web/Tweet/Exec.hs
+++ /dev/null
@@ -1,325 +0,0 @@
--- | Provides IO action that parses command line options and tweetInputs from stdin
-module Web.Tweet.Exec ( exec
-                      , Program (..)
-                      , Command (..)) where
-
-import qualified Data.ByteString.Lazy.Char8 as BSL
-import           Data.Maybe
-import           Data.Monoid
-import           Data.Version
-import           Options.Applicative
-import           Paths_tweet_hs
-import           System.Directory
-import           Web.Tweet
-
--- | Data type for our program: one optional path to a credential file, (optionally) the number of tweetInputs to make, the id of the status you're replying to, and a list of users you wish to mention.
-data Program = Program { subcommand :: Command , cred :: Maybe FilePath , color :: Bool }
-
--- | Data type for a command
--- TODO add boolean option to show ids alongside tweets
-data Command = Timeline { count :: Maybe Int }
-    | SendInput { tweetInputs :: Maybe Int, replyId :: Maybe String, replyh :: Maybe [String] }
-    | Profile { count :: Maybe Int , screenName'' :: Maybe String, withReplies :: Bool, withRetweets :: Bool }
-    | Mentions { count :: Maybe Int }
-    | Markov { screenName' :: String }
-    | Send { tweets :: Maybe Int , replyId :: Maybe String , replyh :: Maybe [String] , userInput :: String }
-    | Sort { screenName' :: String , count :: Maybe Int , includeReplies :: Bool }
-    | Delete { twId :: Integer }
-    | Fav { twId :: Integer }
-    | Unfav { twId :: Integer }
-    | Retweet { twId :: Integer }
-    | Unretweet { twId :: Integer }
-    | List { count :: Maybe Int , screenName' :: String }
-    | Follow { screenName' :: String }
-    | Unfollow { screenName' :: String }
-    | Block { screenName' :: String }
-    | Unblock { screenName' :: String }
-    | Mute { screenName' :: String }
-    | Unmute { screenName' :: String }
-    | Dump { screenName' :: String }
-
--- | query twitter to post stdin with no fancy options
-fromStdIn :: Int -> FilePath -> IO ()
-fromStdIn = threadStdIn [] Nothing
-
--- | Tweet string given to us, as parsed from the command line
-fromCLI :: String -> Int -> FilePath -> IO ()
-fromCLI s = thread s [] Nothing
-
--- | Threaded tweetInputs from stdIn
-threadStdIn :: [String] -> Maybe Int -> Int -> FilePath -> IO ()
-threadStdIn hs idNum num filepath = do
-    contents <- getContents
-    thread contents hs idNum num filepath
-
--- | Executes parser
-exec :: IO ()
-exec = putStrLn bird >> execParser opts >>= select
-    where
-        versionInfo = infoOption ("tweet-hs version: " ++ showVersion version) (short 'v' <> long "version" <> help "Show version")
-        opts        = info (helper <*> versionInfo <*> program)
-            (fullDesc
-            <> progDesc "Tweet and view tweets"
-            <> header "clit - a Command Line Interface Tweeter")
-
--- | Executes program given parsed `Program`
-select :: Program -> IO ()
-select (Program com maybeFile c) = case maybeFile of
-    (Just file) -> selectCommand com (not c) file
-    _ -> selectCommand com (not c) =<< (++ "/.cred.toml") <$> getHomeDirectory
-
--- | Executes subcommand given subcommand + filepath to configuration file
-selectCommand :: Command -> Bool -> FilePath -> IO ()
-selectCommand (Send maybeNum Nothing Nothing input) _ file = fromCLI input (fromMaybe 15 maybeNum) file
-selectCommand (Send maybeNum (Just rId) Nothing input) _ file = thread input [] (pure . read $ rId) (fromMaybe 15 maybeNum) file
-selectCommand (Send maybeNum Nothing (Just h) input) _ file = thread input h Nothing (fromMaybe 15 maybeNum) file
-selectCommand (Send maybeNum (Just rId) (Just h) input) _ file = thread input h (pure . read $ rId) (fromMaybe 15 maybeNum) file
-selectCommand (SendInput maybeNum Nothing Nothing) _ file  = fromStdIn (fromMaybe 15 maybeNum) file
-selectCommand (SendInput maybeNum (Just rId) (Just h)) _ file = threadStdIn h (pure . read $ rId) (fromMaybe 15 maybeNum) file
-selectCommand (SendInput maybeNum (Just rId) Nothing) _ file = threadStdIn [] (pure . read $ rId) (fromMaybe 15 maybeNum) file
-selectCommand (SendInput maybeNum Nothing (Just h)) _ file = threadStdIn h Nothing (fromMaybe 15 maybeNum) file
-selectCommand (Timeline maybeNum) c file = putStrLn =<< showTimeline (fromMaybe 11 maybeNum) c file
-selectCommand (Mentions maybeNum) c file = putStrLn =<< showTweets c <$> mentions (fromMaybe 11 maybeNum) file
-selectCommand (Profile maybeNum n False False) c file = putStrLn =<< showProfile (fromMaybe mempty n) (fromMaybe 11 maybeNum) c file
-selectCommand (Profile maybeNum n True False) c file = putStrLn =<< showFilteredTL [filterReplies] (fromMaybe mempty n) (fromMaybe 11 maybeNum) c file
-selectCommand (Profile maybeNum n False True) c file = putStrLn =<< showFilteredTL [filterRTs] (fromMaybe mempty n) (fromMaybe 11 maybeNum) c file
-selectCommand (Profile maybeNum n True True) c file = putStrLn =<< showFilteredTL [filterReplies, filterRTs] (fromMaybe mempty n) (fromMaybe 11 maybeNum) c file
-selectCommand (Sort n maybeNum False) c file = putStrLn =<< showBest' n (fromMaybe 11 maybeNum) c file
-selectCommand (Sort n maybeNum True) c file = putStrLn =<< showBest n (fromMaybe 11 maybeNum) c file
-selectCommand (List maybeNum n) c file = putStrLn =<< showFavorites (fromMaybe 11 maybeNum) n c file
-selectCommand (Markov n) _ file = do
-    raw <- getMarkov n Nothing file
-    appendFile (n ++ ".txt") (unlines raw)
-    putStrLn $ "Written output to: " ++ n ++ ".txt"
-selectCommand (Delete n) c file = do
-    putStrLn "Deleted:\n"
-    putStrLn =<< showTweets c <$> deleteTweetResponse n file
-selectCommand (Fav n) c file = do
-    putStrLn "Favorited:\n"
-    putStrLn =<< showTweets c <$> favoriteTweetResponse n file
-selectCommand (Unfav n) c file = do
-    putStrLn "Unfavorited:\n"
-    putStrLn =<< showTweets c <$> unfavoriteTweetResponse n file
-selectCommand (Retweet n) c file = do
-    putStrLn "Retweeted:\n"
-    putStrLn =<< showTweets c <$> retweetTweetResponse n file
-selectCommand (Unretweet n) c file = do
-    putStrLn "Unretweeted:\n"
-    putStrLn =<< showTweets c <$> unretweetTweetResponse n file
-selectCommand (Follow sn) _ file = do
-    follow sn file
-    putStrLn ("..." ++ sn ++ " followed successfully!")
-selectCommand (Unfollow sn) _ file = do
-    unfollow sn file
-    putStrLn ("..." ++ sn ++ " unfollowed successfully!")
-selectCommand (Block sn) _ file = do
-    block sn file
-    putStrLn ("..." ++ sn ++ " blocked successfully")
-selectCommand (Unblock sn) _ file = do
-    unblock sn file
-    putStrLn ("..." ++ sn ++ " unblocked successfully")
-selectCommand (Mute sn) _ file = do
-    mute sn file
-    putStrLn ("..." ++ sn ++ " muted successfully")
-selectCommand (Unmute sn) _ file = do
-    unmute sn file
-    putStrLn ("..." ++ sn ++ " unmuted successfully")
-selectCommand (Dump sn) _ file = BSL.putStrLn =<< getProfileRaw sn 3200 file Nothing
-
--- | Parser to return a program datatype
-program :: Parser Program
-program = Program
-    <$> hsubparser
-        (command "send" (info tweet (progDesc "Send a tweet from the command-line"))
-        <> command "input" (info tweetInput (progDesc "Send a tweet from stdIn"))
-        <> command "view" (info timeline (progDesc "Get your timeline"))
-        <> command "user" (info profile (progDesc "Get a user's profile"))
-        <> command "markov" (info markov (progDesc "Grab tweets en masse."))
-        <> command "hits" (info best (progDesc "View a user's top tweets."))
-        <> command "del" (info delete (progDesc "Delete a tweet.")) -- TODO delete/favorite in bunches!
-        <> command "fav" (info fav (progDesc "Favorite a tweet"))
-        <> command "ufav" (info unfav (progDesc "Unfavorite a tweet"))
-        <> command "urt" (info unrt (progDesc "Un-retweet a tweet"))
-        <> command "rt" (info rt (progDesc "Retweet a tweet"))
-        <> command "follow" (info fol (progDesc "Follow a user"))
-        <> command "unfollow" (info unfol (progDesc "Unfollow a user"))
-        <> command "list" (info list (progDesc "List a user's favorites"))
-        <> command "dump" (info dump (progDesc "Dump tweets (for debugging)"))
-        <> command "block" (info blockParser (progDesc "Block a user"))
-        <> command "unblock" (info unblockParser (progDesc "Unblock a user"))
-        <> command "mute" (info muteParser (progDesc "Mute a user"))
-        <> command "unmute" (info unmuteParser (progDesc "Unmute a user"))
-        <> command "mentions" (info mentionsParser (progDesc "Fetch mentions")))
-    <*> optional (strOption
-        (long "cred"
-        <> short 'c'
-        <> metavar "CREDENTIALS"
-        <> completer (bashCompleter "file -X '!*.toml' -o plusdirs")
-        <> help "path to credentials"))
-    <*> switch
-        (long "color"
-        <> short 'l'
-        <> help "Turn off colorized terminal output.")
-
--- | Parser for the view subcommand
-timeline :: Parser Command
-timeline = Timeline
-    <$> optional (read <$> strOption
-        (long "count"
-        <> short 'n'
-        <> metavar "NUM"
-        <> help "number of tweetInputs to fetch, default 5"))
-
--- | Parser for the markov subcommand
-markov :: Parser Command
-markov = Markov <$> user
-
--- | Parser for the follow subcommand
-fol :: Parser Command
-fol = Follow <$> user
-
--- | Parser for the block subcommand
-blockParser :: Parser Command
-blockParser = Block <$> user
-
--- | Parser for the unblock subcommand
-unblockParser :: Parser Command
-unblockParser = Unblock <$> user
-
--- | Parser for the dump subcommand
-dump :: Parser Command
-dump = Dump <$> user
-
--- | Parser for the unfollow subcommand
-unfol :: Parser Command
-unfol = Unfollow <$> user
-
--- | Parser for the list subcommand
-list :: Parser Command
-list = List
-    <$> optional (read <$> strOption
-        (long "count"
-        <> short 'n'
-        <> metavar "NUM"
-        <> help "Number of tweetInputs to fetch, default 12"))
-    <*> user
-
--- | Parser for the unfollow subcommand
-muteParser :: Parser Command
-muteParser = Mute <$> user
-
--- | Parser for the unfollow subcommand
-unmuteParser :: Parser Command
-unmuteParser = Unmute <$> user
-
--- | Parse a user screen name
-user :: Parser String
-user = argument str
-    (metavar "SCREEN_NAME"
-    <> help "Screen name of user.")
-
--- | Parser for the del subcommand
-delete :: Parser Command
-delete = Delete <$> getInt
-
--- | Parser for the fav subcommand
-fav :: Parser Command
-fav = Fav <$> getInt
-
--- | Parser for the fav subcommand
-unfav :: Parser Command
-unfav = Unfav <$> getInt
-
--- | Parser for the fav subcommand
-unrt :: Parser Command
-unrt = Unretweet <$> getInt
-
--- | Parser for the fav subcommand
-rt :: Parser Command
-rt = Retweet <$> getInt
-
--- | Parser for the del subcommand
-getInt :: Parser Integer
-getInt = read <$> argument str
-    (metavar "TWEET_ID"
-    <> help "ID of tweet")
-
--- | Parser for the user subcommand
-profile :: Parser Command
-profile = Profile
-    <$> optional (read <$> strOption
-        (long "count"
-        <> short 'n'
-        <> metavar "NUM"
-        <> help "Number of tweetInputs to fetch, default 12"))
-    <*> optional user
-    <*> switch (
-           long "no-replies"
-        <> short 'r'
-        <> help "Don't display replies.")
-    <*> switch (
-           long "no-retweets"
-        <> short 't'
-        <> help "Don't display retweets.")
-
--- | Parser for the mention subcommand
-mentionsParser :: Parser Command
-mentionsParser = Mentions
-    <$> optional (read <$> strOption
-        (long "count"
-        <> short 'n'
-        <> metavar "NUM"
-        <> help "Number of tweetInputs to fetch, default 12"))
-
--- | Parse best tweets
-best :: Parser Command
-best = Sort
-    <$> argument str
-        (metavar "SCREEN_NAME"
-        <> help "Screen name of user you want to view.")
-    <*> optional (read <$> strOption
-        (long "count"
-        <> short 'n'
-        <> metavar "NUM"
-        <> help "Number of tweetInputs to fetch, default 12"))
-    <*> switch
-        (long "replies"
-        <> short 'r'
-        <> help "Include replies in your all-time hits")
-
--- | Parser for the send subcommand
-tweet :: Parser Command
-tweet = Send
-    <$> optional (read <$> strOption
-        (long "tweets"
-        <> short 't'
-        <> metavar "NUM"
-        <> help "Number of tweetInputs in a row, default 15"))
-    <*> optional (strOption
-        (long "reply"
-        <> short 'r'
-        <> help "id of status to reply to - be sure to include their handle, e.g. @my_build_errors"))
-    <*> optional (some $ strOption
-        (long "handle"
-        <> short 'h'
-        <> metavar "HANDLE1"
-        <> help "h to include in replies"))
-    <*> (unwords <$> some (argument str
-        (metavar "TEXT"
-        <> help "text of tweet to be sent")))
-
--- | Parser for the input command
-tweetInput :: Parser Command
-tweetInput = SendInput
-    <$> optional (read <$> strOption
-        (long "tweets"
-        <> short 't'
-        <> metavar "NUM"
-        <> help "Number of tweets in a row, default 15"))
-    <*> optional (strOption
-        (long "reply"
-        <> short 'r'
-        <> help "id of status to reply to - be sure to include their handle, e.g. @my_build_errors"))
-    <*> optional (some $ argument str
-        (metavar "HANDLE1"
-        <> help "h to include in replies"))
diff --git a/src/Web/Tweet/Parser.hs b/src/Web/Tweet/Parser.hs
--- a/src/Web/Tweet/Parser.hs
+++ b/src/Web/Tweet/Parser.hs
@@ -1,5 +1,6 @@
 {-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
 {-# LANGUAGE OverloadedStrings #-}
+
 -- | Module containing parsers for tweet and response data.
 module Web.Tweet.Parser ( parseTweet
                         , getData ) where
@@ -10,7 +11,6 @@
 import Text.Megaparsec.Byte.Lexer as L
 import Text.Megaparsec
 import Web.Tweet.Types
-import Data.Monoid
 import qualified Data.Map as M
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as TE
@@ -97,8 +97,7 @@
     string $ "\"" <> str <> "\":"
     open <- optional $ char '\"'
     let forbidden = if isJust open then ("\\\"" :: String) else ("\\\"," :: String)
-    want <- many $ parseHTMLChar <|> noneOf forbidden <|> specialChar '\"' <|> specialChar '/' <|> newlineChar <|> emojiChar <|> unicodeChar -- TODO modify parsec to make this parallel?
-    pure want
+    many $ parseHTMLChar <|> noneOf forbidden <|> specialChar '\"' <|> specialChar '/' <|> newlineChar <|> emojiChar <|> unicodeChar -- TODO modify parsec to make this parallel?
 
 -- | Parse a newline
 newlineChar :: Parser Char
diff --git a/src/Web/Tweet/Types.hs b/src/Web/Tweet/Types.hs
--- a/src/Web/Tweet/Types.hs
+++ b/src/Web/Tweet/Types.hs
@@ -4,9 +4,9 @@
 -- | Exports the `Tweet` type, a datatype for building tweets easily
 module Web.Tweet.Types where
 
-import           Control.Lens
 import           Data.Default
 import           GHC.Generics
+import           Lens.Micro
 import           Web.Authenticate.OAuth
 
 -- | Data type for our request: consists of the status text, whether to trium u information in the response, the handles to mention, and optionally the id of the status to reply to.
diff --git a/src/Web/Tweet/Utils.hs b/src/Web/Tweet/Utils.hs
--- a/src/Web/Tweet/Utils.hs
+++ b/src/Web/Tweet/Utils.hs
@@ -15,12 +15,12 @@
   ) where
 
 import           Control.Composition
-import           Control.Lens
 import qualified Data.ByteString             as BS2
 import qualified Data.ByteString.Char8       as BS
 import           Data.List
 import           Data.List.Extra
 import           Data.Void
+import           Lens.Micro.Extras
 import           Text.Megaparsec
 import           Web.Tweet.Parser
 import           Web.Tweet.Parser.FastParser hiding (text)
diff --git a/src/Web/Tweet/Utils/API.hs b/src/Web/Tweet/Utils/API.hs
--- a/src/Web/Tweet/Utils/API.hs
+++ b/src/Web/Tweet/Utils/API.hs
@@ -54,14 +54,6 @@
     putStr $ if code == 200 then "" else "failed :(\n error code: " ++ show code ++ "\n"
     pure . responseBody $ response
 
--- | print output of a request and return status id as an `Int`.
-{-responseInt :: Request -> Manager -> IO Int
-responseInt request manager = do
-    response <- httpLbs request manager
-    let code = statusCode $ responseStatus response
-    putStrLn $ if (code == 200) then "POST succesful!" else "failed :(\n error code: " ++ (show code)
-    return $ (read . (takeWhile (/=',')) . (drop 52)) (BSL.unpack $ responseBody response)-} -- TODO use the more general parser
-
 -- | Convert a tweet to a percent-encoded url for querying an API
 urlString :: Tweet -> String
 urlString tweet = concat [ "?status="
@@ -77,7 +69,7 @@
 strEncode :: String -> String
 strEncode = BS.unpack . paramEncode . encodeUtf8 . T.pack
 
--- | Percent-encode the status update so it's fit for a URL and UTF-encode it as well.
+-- | Percent-encode the status update so it's fit for a URL.
 tweetEncode :: Tweet -> BS.ByteString
 tweetEncode tweet = paramEncode . encodeUtf8 $ handleStr `T.append` content
     where content   = T.pack . _status $ tweet
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,7 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
 
--- import qualified Data.ByteString             as BS
-import           Data.Monoid
 import           System.Environment
 import           Test.Hspec
 import           Web.Tweet.Parser.FastParser
diff --git a/tweet-hs.cabal b/tweet-hs.cabal
--- a/tweet-hs.cabal
+++ b/tweet-hs.cabal
@@ -1,127 +1,148 @@
-name:                tweet-hs
-version:             1.0.1.35
-synopsis:            Command-line tool for twitter
-description:         a Command Line Interface Tweeter
-homepage:            https://github.com/vmchale/command-line-tweeter#readme
-license:             BSD3
-license-file:        LICENSE
-author:              Vanessa McHale
-maintainer:          vanessa.mchale@reconfigure.io
-copyright:           2016, 2017 Vanessa McHale
-category:            Web
-build-type:          Simple
-stability:           stable
-extra-source-files:  README.md, cabal.project.local, bash/mkCompletions, test/data
-cabal-version:       >=1.10
+cabal-version: >=1.10
+name: tweet-hs
+version: 1.0.1.36
+license: BSD3
+license-file: LICENSE
+copyright: 2016, 2017 Vanessa McHale
+maintainer: vanessa.mchale@reconfigure.io
+author: Vanessa McHale
+stability: stable
+homepage: https://github.com/vmchale/command-line-tweeter#readme
+synopsis: Command-line tool for twitter
+description:
+    a Command Line Interface Tweeter
+category: Web
+build-type: Simple
+extra-source-files:
+    README.md
+    cabal.project.local
+    bash/mkCompletions
+    test/data
 
-Flag llvm-fast {
-  Description: Enable build with llvm backend
-  Default: False
-}
+source-repository head
+    type: git
+    location: https://hub.darcs.net/vmchale/tweet-hs
 
-Flag library {
-  Description: Don't build an executable
-  Default:     False
-}
+flag llvm-fast
+    description:
+        Enable build with llvm backend
+    default: False
 
-Flag development {
-  Description: Enable -Werror
-  Default: False
-  Manual: True
-}
+flag library
+    description:
+        Don't build an executable
+    default: False
 
-Flag parallel-gc {
-  Description: Use parallel garbage collector
-  Default:     False
-}
+flag development
+    description:
+        Enable -Werror
+    default: False
+    manual: True
 
+flag parallel-gc
+    description:
+        Use parallel garbage collector
+    default: False
+
 library
-  hs-source-dirs:      src
-  exposed-modules:     Web.Tweet
-                     , Web.Tweet.Exec
-                     , Web.Tweet.Parser.FastParser
-                     , Web.Tweet.Parser
-                     , Web.Tweet.Sign
-                     , Web.Tweet.API
-                     , Web.Tweet.Utils
-                     -- FIXME move to other-modules!!
-  other-modules:       Web.Tweet.Types
-                     , Web.Tweet.Utils.Colors
-                     , Web.Tweet.API.Internal
-                     , Web.Tweet.Utils.API
-                     , Paths_tweet_hs
-  build-depends:       base >= 4.9 && < 5
-                     , http-client-tls
-                     , http-client
-                     , http-types
-                     , authenticate-oauth
-                     , megaparsec >= 6.0
-                     , bytestring
-                     , split
-                     , optparse-applicative 
-                     , lens
-                     , unordered-containers
-                     , htoml-megaparsec
-                     , data-default
-                     , text
-                     , containers
-                     , ansi-wl-pprint
-                     , directory
-                     , composition-prelude
-                     , extra
-                     , aeson
-  default-language:    Haskell2010
-  default-extensions:  LambdaCase
-  if flag(development)
-    ghc-options:       -Werror
-  ghc-options:         -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates
+    exposed-modules:
+        Web.Tweet
+        Web.Tweet.Parser.FastParser
+        Web.Tweet.Parser
+        Web.Tweet.Sign
+        Web.Tweet.API
+        Web.Tweet.Utils
+    hs-source-dirs: src
+    other-modules:
+        Web.Tweet.Types
+        Web.Tweet.Utils.Colors
+        Web.Tweet.API.Internal
+        Web.Tweet.Utils.API
+    default-language: Haskell2010
+    default-extensions: LambdaCase
+    ghc-options: -Wall -Wincomplete-uni-patterns
+                 -Wincomplete-record-updates
+    build-depends:
+        base >=4.11 && <5,
+        http-client-tls -any,
+        http-client -any,
+        http-types -any,
+        authenticate-oauth -any,
+        megaparsec >=6.0,
+        bytestring -any,
+        split -any,
+        microlens -any,
+        unordered-containers -any,
+        htoml-megaparsec -any,
+        data-default -any,
+        text -any,
+        containers -any,
+        ansi-wl-pprint -any,
+        composition-prelude -any,
+        extra -any,
+        aeson -any
+    
+    if flag(development)
+        ghc-options: -Werror
 
 executable tweet
-  if flag(library)
-    Buildable: False
-  else
-    Buildable: True
-  hs-source-dirs:      app
-  main-is:             Main.hs
-  if flag(llvm-fast)
-    ghc-options:       -fllvm -optlo-O3 -O3
-  if flag(parallel-gc)
-    ghc-options:       -rtsopts -with-rtsopts=-N
-  if flag(development)
-    ghc-options:       -Werror
-  ghc-options:         -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates
-  build-depends:       base
-                     , tweet-hs 
-  default-language:    Haskell2010
-
-benchmark tweeths-bench
-  type:                exitcode-stdio-1.0
-  hs-source-dirs:      bench
-  main-is:             Bench.hs
-  build-depends:       base
-                       , criterion
-                       , tweet-hs
-                       , bytestring
-                       , megaparsec
-  if flag(llvm-fast)
-    ghc-options:       -fllvm -optlo-O3 -O3
-  if flag(development)
-    ghc-options:       -Werror
-  ghc-options:         -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates
-  default-language:    Haskell2010
+    main-is: Main.hs
+    hs-source-dirs: app
+    other-modules:
+        Paths_tweet_hs
+    default-language: Haskell2010
+    ghc-options: -Wall -Wincomplete-uni-patterns
+                 -Wincomplete-record-updates
+    build-depends:
+        base -any,
+        tweet-hs -any,
+        optparse-applicative -any,
+        directory -any,
+        bytestring -any
+    
+    if flag(library)
+        buildable: False
+    
+    if flag(llvm-fast)
+        ghc-options: -fllvm -optlo-O3 -O3
+    
+    if flag(parallel-gc)
+        ghc-options: -rtsopts -with-rtsopts=-N
+    
+    if flag(development)
+        ghc-options: -Werror
 
 test-suite tweeths-test
-  type:                exitcode-stdio-1.0
-  hs-source-dirs:      test
-  main-is:             Spec.hs
-  build-depends:       base
-                     , tweet-hs
-                     , hspec
-  if flag(development)
-    ghc-options:       -Werror
-  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates
-  default-language:    Haskell2010
+    type: exitcode-stdio-1.0
+    main-is: Spec.hs
+    hs-source-dirs: test
+    default-language: Haskell2010
+    ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
+                 -Wincomplete-uni-patterns -Wincomplete-record-updates
+    build-depends:
+        base -any,
+        tweet-hs -any,
+        hspec -any
+    
+    if flag(development)
+        ghc-options: -Werror
 
-source-repository head
-  type:     git
-  location: https://hub.darcs.net/vmchale/tweet-hs
+benchmark tweeths-bench
+    type: exitcode-stdio-1.0
+    main-is: Bench.hs
+    hs-source-dirs: bench
+    default-language: Haskell2010
+    ghc-options: -Wall -Wincomplete-uni-patterns
+                 -Wincomplete-record-updates
+    build-depends:
+        base -any,
+        criterion -any,
+        tweet-hs -any,
+        bytestring -any,
+        megaparsec -any
+    
+    if flag(llvm-fast)
+        ghc-options: -fllvm -optlo-O3 -O3
+    
+    if flag(development)
+        ghc-options: -Werror
