diff --git a/ats-pkg.cabal b/ats-pkg.cabal
--- a/ats-pkg.cabal
+++ b/ats-pkg.cabal
@@ -1,5 +1,5 @@
 name:                ats-pkg
-version:             2.2.0.18
+version:             2.2.1.0
 synopsis:            A build tool for ATS
 description:         A collection of scripts to simplify building ATS projects.
 homepage:            https://github.com/vmchale/atspkg#readme
diff --git a/src/Language/ATS/Package/Build.hs b/src/Language/ATS/Package/Build.hs
--- a/src/Language/ATS/Package/Build.hs
+++ b/src/Language/ATS/Package/Build.hs
@@ -53,7 +53,7 @@
 build :: [String] -- ^ Targets
       -> IO ()
 build rs = bool (mkPkgEmpty [buildAll Nothing]) (mkPkgEmpty mempty) =<< check Nothing
-    where mkPkgEmpty ts = mkPkg False False ts rs Nothing
+    where mkPkgEmpty ts = mkPkg False False ts rs Nothing 1
 
 -- TODO clean generated ATS
 mkClean :: Rules ()
@@ -105,14 +105,23 @@
 manTarget :: Text -> FilePath
 manTarget m = TL.unpack m -<.> "1"
 
-mkTest :: Rules ()
-mkTest =
-    "test" ~> do
+mkPhony :: String -> (String -> String) -> (Pkg -> [Bin]) -> [String] -> Rules ()
+mkPhony cmdStr f select rs =
+    cmdStr ~> do
         config <- getConfig Nothing
-        let tests = fmap (TL.unpack . target) . test $ config
-        need tests
-        mapM_ cmd_ tests
+        let runs = bool (filter (/= cmdStr) rs) (fmap (TL.unpack . target) . select $ config) (rs == [cmdStr])
+        need runs
+        mapM_ cmd_ (f <$> runs)
 
+mkValgrind :: [String] -> Rules ()
+mkValgrind = mkPhony "valgrind" ("valgrind " <>) bin
+
+mkTest :: [String] -> Rules ()
+mkTest = mkPhony "test" id test
+
+mkRun :: [String] -> Rules ()
+mkRun = mkPhony "run" id bin
+
 options :: Bool -- ^ Whether to rebuild config
         -> Bool -- ^ Whether to rebuild all targets
         -> [String] -- ^ A list of targets
@@ -131,18 +140,18 @@
 cleanConfig ["clean"] = pure undefined
 cleanConfig _         = getConfig Nothing
 
--- TODO verbosity?
 mkPkg :: Bool -- ^ Whether to ignore cached package config
       -> Bool -- ^ Rebuild all targets
       -> [IO ()] -- ^ Setup
       -> [String] -- ^ Targets
       -> Maybe String -- ^ Target triple
+      -> Int -- ^ Verbosity
       -> IO ()
-mkPkg rb rba setup rs tgt = do
+mkPkg rb rba setup rs tgt _ = do
     cfg <- cleanConfig rs
     let opt = options rb rba $ pkgToTargets cfg rs
     shake opt $
-        foldr (>>) (pure ())
+        mconcat
             [ want rs
             , mkClean
             , pkgToAction setup rs tgt =<< cleanConfig rs
@@ -165,13 +174,9 @@
         (Just m) -> want . bool bins (manTarget m : bins) =<< pandoc
         Nothing  -> want bins
 
-bits :: Rules ()
-bits = foldr (>>) (pure ())
-    [ mkTest
-    , mkManpage
-    , mkInstall
-    , mkConfig
-    ]
+bits :: [String] -> Rules ()
+bits rs = mconcat $ [ mkManpage, mkInstall, mkConfig ] <>
+    sequence [ mkRun, mkTest, mkValgrind ] rs
 
 pkgToTargets :: Pkg -> [FilePath] -> [FilePath]
 pkgToTargets ~Pkg{..} [] = TL.unpack . target <$> bin
@@ -197,7 +202,7 @@
         let bins = TL.unpack . target <$> bs
         setTargets rs bins mt
 
-        cDepsRules >> bits
+        cDepsRules >> bits rs
 
         mapM_ g (bs ++ ts)
 
diff --git a/src/Language/ATS/Package/Exec.hs b/src/Language/ATS/Package/Exec.hs
--- a/src/Language/ATS/Package/Exec.hs
+++ b/src/Language/ATS/Package/Exec.hs
@@ -32,12 +32,15 @@
                      , _recache    :: Bool
                      , _archTarget :: Maybe String
                      , _rebuildAll :: Bool
+                     , _verbosity  :: Int
                      }
              | Clean
-             | Test
+             | Test { _targets :: [String] }
              | Fetch { _url :: String }
              | Nuke
              | Upgrade
+             | Valgrind { _targets :: [String] }
+             | Run { _targets :: [String] }
 
 command' :: Parser Command
 command' = hsubparser
@@ -45,17 +48,31 @@
     <> command "clean" (info (pure Clean) (progDesc "Clean current project directory"))
     <> command "remote" (info fetch (progDesc "Fetch and install a binary package"))
     <> command "build" (info build' (progDesc "Build current package targets"))
-    <> command "test" (info (pure Test) (progDesc "Test current package"))
+    <> command "test" (info test' (progDesc "Test current package"))
     <> command "nuke" (info (pure Nuke) (progDesc "Uninstall all globally installed libraries"))
     <> command "upgrade" (info (pure Upgrade) (progDesc "Upgrade to the latest version of atspkg"))
+    <> command "valgrind" (info valgrind (progDesc "Run generated binaries through valgrind"))
+    <> command "run" (info run' (progDesc "Run generated binaries"))
     )
 
+run' :: Parser Command
+run' = Run <$> targets "run"
+
+test' :: Parser Command
+test' = Test <$> targets "test"
+
+valgrind :: Parser Command
+valgrind = Valgrind <$> targets "run with valgrind"
+
+targets :: String -> Parser [String]
+targets s = many
+    (argument str
+    (metavar "TARGET"
+    <> help ("Targets to " <> s)))
+
 build' :: Parser Command
 build' = Build
-    <$> many
-        (argument str
-        (metavar "TARGET"
-        <> help "Targets to build"))
+    <$> targets "build"
     <*> switch
         (long "no-cache"
         <> short 'c'
@@ -69,6 +86,8 @@
         (long "rebuild"
         <> short 'r'
         <> help "Force rebuild of all targets")
+    <*> (length <$>
+        many (flag' () (short 't' <> long "verbose")))
 
 fetch :: Parser Command
 fetch = Fetch <$>
@@ -82,26 +101,28 @@
     fetchDeps True mempty [ATSDependency lib dirName url' undefined] [] True
     ps <- getSubdirs p
     pkgDir <- fromMaybe p <$> findFile (p:ps) "atspkg.dhall"
-    let a = withCurrentDirectory (takeDirectory pkgDir) (mkPkg False False mempty ["install"] Nothing)
+    let a = withCurrentDirectory (takeDirectory pkgDir) (mkPkg False False mempty ["install"] Nothing 0)
     bool (buildAll (Just pkgDir) >> a) a =<< check (Just pkgDir)
 
 exec :: IO ()
 exec = execParser wrapper >>= run
 
-runHelper :: Bool -> Bool -> [String] -> Maybe String -> IO ()
-runHelper rb rba rs tgt = bool
-    (mkPkg rb rba [buildAll Nothing] rs tgt)
-    (mkPkg rb rba mempty rs tgt)
+runHelper :: Bool -> Bool -> [String] -> Maybe String -> Int -> IO ()
+runHelper rb rba rs tgt v = bool
+    (mkPkg rb rba [buildAll Nothing] rs tgt v)
+    (mkPkg rb rba mempty rs tgt v)
     =<< check Nothing
 
 run :: Command -> IO ()
 run Upgrade = upgradeAtsPkg
 run Nuke = cleanAll
 run (Fetch u) = fetchPkg u
-run Clean = mkPkg False False mempty ["clean"] Nothing
-run (Build rs rb tgt rba) = runHelper rb rba rs tgt
-run c = runHelper False False rs Nothing
+run Clean = mkPkg False False mempty ["clean"] Nothing 0
+run (Build rs rb tgt rba v) = runHelper rb rba rs tgt v
+run c = runHelper False False rs Nothing 0
     where rs = g c
-          g Install = ["install"]
-          g Test    = ["test"]
-          g _       = undefined
+          g Install       = ["install"]
+          g (Test  ts)    = "test" : ts
+          g (Valgrind ts) = "valgrind" : ts
+          g (Run ts)      = "run" : ts
+          g _             = undefined
