diff --git a/cblrepo.cabal b/cblrepo.cabal
--- a/cblrepo.cabal
+++ b/cblrepo.cabal
@@ -1,5 +1,5 @@
 name: cblrepo
-version: 0.12
+version: 0.13
 cabal-version: >= 1.6
 license: OtherLicense
 license-file: LICENSE-2.0
@@ -30,8 +30,8 @@
         directory ==1.2.*, Cabal ==1.18.*, json ==0.7.*,
         bytestring ==0.10.*, tar ==0.4.*, zlib ==0.5.*, mtl >=2.0 && <2.2,
         process ==1.2.*, Unixutils ==1.52.*, unix ==2.7.*,
-        ansi-wl-pprint ==0.6.*, aeson ==0.7.* && >= 0.6.2,
-        optparse-applicative ==0.10.*, safe
+        ansi-wl-pprint ==0.6.*, aeson ==0.8.*,
+        optparse-applicative ==0.11.*, safe
 
 Source-Repository head
     Type:                 git
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -43,23 +43,23 @@
 
 cmdAddPkgOpts = CmdAdd
     <$> strOption (long "patchdir" <> value "patches" <> help "Location of patches (patches)")
-    <*> option readerGhcVersion (long "ghc-version" <> value ghcDefVersion <> help "GHC version to use")
+    <*> option ghcVersionArgReader (long "ghc-version" <> value ghcDefVersion <> help "GHC version to use")
     <*> many (option ghcPkgArgReader (short 'g' <> long "ghc-pkg" <> metavar "PKG,VER" <> help "GHC base package (multiple)"))
     <*> many (option distroPkgArgReader (short 'd' <> long "distro-pkg" <> metavar "PKG,VER,REL" <> help "Distro package (multiple)"))
-    <*> many (option strCblFileArg (short 'f' <> long "cbl-file" <> metavar "FILE[:flag,-flag]" <> help "CABAL file (multiple)"))
-    <*> many (argument strCblPkgArg (metavar "PKGNAME,VERSION[:flag,-flag] ..."))
+    <*> many (option strCblFileArgReader (short 'f' <> long "cbl-file" <> metavar "FILE[:flag,-flag]" <> help "CABAL file (multiple)"))
+    <*> many (argument strCblPkgArgReader (metavar "PKGNAME,VERSION[:flag,-flag] ..."))
 
 cmdAddPkgCmd = command "add" (info (helper <*> cmdAddPkgOpts)
     (fullDesc <> progDesc "Add a package to the database"))
 
 cmdBumpPkgsOpts = CmdBumpPkgs
     <$> switch (long "inclusive" <> help "Include the listed packages")
-    <*> some (argument Just (metavar "PKGNAME ..."))
+    <*> some (strArgument (metavar "PKGNAME ..."))
 cmdBumpPkgsCmd = command "bump" (info (helper <*> cmdBumpPkgsOpts)
     (fullDesc <> progDesc "Bump packages that need it after updating the named packages"))
 
 cmdBuildPkgsOpts = CmdBuildPkgs
-    <$> some (argument Just (metavar "PKGNAME ..."))
+    <$> some (strArgument (metavar "PKGNAME ..."))
 cmdBuildPkgsCmd = command "build" (info (helper <*> cmdBuildPkgsOpts)
     (fullDesc <> progDesc "Re-order packages into a good build order"))
 
@@ -69,7 +69,7 @@
 
 cmdVersionsOpts = CmdVersions
     <$> switch (short 'l' <> long "latest" <> help "List only the latest version of packages")
-    <*> some (argument Just (metavar "PKGNAME ..."))
+    <*> some (strArgument (metavar "PKGNAME ..."))
 cmdVersionsCmd = command "versions" (info (helper <*> cmdVersionsOpts)
     (fullDesc <> progDesc "List available versions of packages"))
 
@@ -88,15 +88,15 @@
     (fullDesc <> progDesc "List packages in repo"))
 
 cmdUrlsOpts = CmdUrls
-    <$> some (argument (strPairArg ',') (metavar "PKGNAME,VERSION ..."))
+    <$> some (option pkgNVersionArgReader (metavar "PKGNAME,VERSION ..."))
 cmdUrlsCmd = command "urls" (info (helper <*> cmdUrlsOpts)
     (fullDesc <> progDesc "List urls of CABAL files for the given packages"))
 
 cmdPkgBuildOpts = CmdPkgBuild
-    <$> option readerGhcVersion (long "ghc-version" <> value ghcDefVersion <> help "GHC version to use in PKGBUILD")
+    <$> option ghcVersionArgReader (long "ghc-version" <> value ghcDefVersion <> help "GHC version to use in PKGBUILD")
     <*> option auto (long "ghc-release" <> value 1 <> help "GHC release to use in PKGBUILD")
     <*> strOption (long "patchdir" <> value "patches" <> help "Location of patches (patches)")
-    <*> some (argument Just (metavar "PKGNAME ..."))
+    <*> some (strArgument (metavar "PKGNAME ..."))
 cmdPkgBuildCmd = command "pkgbuild" (info (helper <*> cmdPkgBuildOpts)
     (fullDesc <> progDesc "Create PKGBUILD other files necessary for an Arch package"))
 
@@ -107,7 +107,7 @@
     (fullDesc <> progDesc "Convert an old database to the new format"))
 
 cmdRemovePkgOpts = CmdRemovePkg
-    <$> some (argument Just (metavar "PKGNAME ..."))
+    <$> some (strArgument (metavar "PKGNAME ..."))
 cmdRemovePkgCmd = command "rm" (info (helper <*> cmdRemovePkgOpts)
     (fullDesc <> progDesc "Remove packages"))
 
diff --git a/src/Urls.hs b/src/Urls.hs
--- a/src/Urls.hs
+++ b/src/Urls.hs
@@ -19,10 +19,11 @@
 import Util.Misc
 
 import Control.Monad.Reader
+import Distribution.Text (display)
 
 urls :: Command ()
 urls = do
     pkgs <- optGet $ pkgVers . optsCmd
     liftIO $ mapM_ (putStrLn . createUrl) pkgs
 
-createUrl (pkg, ver) = "http://hackage.haskell.org/packages/archive/" ++ pkg ++ "/" ++ ver ++ "/" ++ pkg ++ ".cabal"
+createUrl (pkg, ver) = "http://hackage.haskell.org/packages/archive/" ++ pkg ++ "/" ++ display ver ++ "/" ++ pkg ++ ".cabal"
diff --git a/src/Util/Misc.hs b/src/Util/Misc.hs
--- a/src/Util/Misc.hs
+++ b/src/Util/Misc.hs
@@ -37,6 +37,7 @@
 import Distribution.Verbosity
 import Distribution.Version
 import Options.Applicative
+import Options.Applicative.Types
 import Safe (lastMay)
 import System.Directory
 import System.Exit
@@ -45,7 +46,7 @@
 import System.Posix.Files
 import System.Process
 import System.Unix.Directory
-import Text.ParserCombinators.ReadP (readP_to_S)
+import Text.ParserCombinators.ReadP hiding (many)
 import qualified Data.ByteString.Lazy.Char8 as BS
 
 -- {{{1 dependency
@@ -73,66 +74,93 @@
 indexFileName = "index.tar.gz"
 
 -- {{{1 command line parser helpers
-readerGhcVersion :: String -> ReadM Version
-readerGhcVersion arg = case lastMay $ readP_to_S parseVersion arg of
-    Just (v, "") -> return v
-    _ -> fail $ "cannot parse value `" ++ arg ++ "`"
+readPkgNVersion :: ReadP (String, Version)
+readPkgNVersion = do
+    n <- many (satisfy (/= ','))
+    char ','
+    v <- parseVersion
+    return (n, v)
 
-splitOnElem :: Eq a => a -> [a] -> [[a]]
-splitOnElem e l =
-    let p@(a, b) = break (== e) l
-    in case p of
-        (_, []) -> [a]
-        (_, _) -> a : splitOnElem e (tail b)
+readFlag :: ReadP (FlagName, Bool)
+readFlag = readNegFlag <++ readPosFlag
+    where
+        readNegFlag = do
+            char '-'
+            n <- many (satisfy (/= ','))
+            return (FlagName n, False)
 
-strPairArg :: Monad m => Char -> String -> m (String, String)
-strPairArg c s =
-    case splitOnElem c s of
-        [a, b] -> return (a, b)
-        _ -> error $ "Failed to parse pair: " ++ s
+        readPosFlag = do
+            n0 <- get
+            n <- many (satisfy (/= ','))
+            return (FlagName (n0 : n), True)
 
-strTripleArg :: Monad m => Char -> String -> m (String, String, String)
-strTripleArg c s =
-    case splitOnElem c s of
-        [a, b, c] -> return (a, b, c)
-        _ -> error $ "Failed to parse triple: " ++ s
+ghcVersionArgReader :: ReadM Version
+ghcVersionArgReader = do
+    arg <- readerAsk
+    case lastMay $ readP_to_S parseVersion arg of
+        Just (v, "") -> return v
+        _ -> fail $ "cannot parse value `" ++ arg ++ "`"
 
-ghcPkgArgReader :: String -> ReadM (String, Version)
-ghcPkgArgReader s = do
-    (pkgName, verStr) <- strPairArg ',' s
-    case simpleParse verStr of
-        Nothing -> fail $ "Failed to parse version in " ++ s
-        Just v -> return (pkgName, v)
+pkgNVersionArgReader :: ReadM (String, Version)
+pkgNVersionArgReader = do
+    s <- readerAsk
+    case lastMay (readP_to_S readPkgNVersion s) of
+        Just (r, "") -> return r
+        _ -> fail $ "Cannot parse '" ++ s ++ "' as PKG,VER"
 
-distroPkgArgReader :: String -> ReadM (String, Version, String)
-distroPkgArgReader s = do
-    (pkgName, verStr, revStr) <- strTripleArg ',' s
-    case simpleParse verStr of
-        Nothing -> fail $ "Failed to parse version in " ++ s
-        Just v -> return (pkgName, v, revStr)
+ghcPkgArgReader :: ReadM (String, Version)
+ghcPkgArgReader = pkgNVersionArgReader
 
-strCblFileArg :: String -> ReadM (FilePath, FlagAssignment)
-strCblFileArg s = let
-        flagReader ('-':cs) = (FlagName cs, False)
-        flagReader cs = (FlagName cs, True)
-        (fn:fs) = splitOnElem ':' s
-        fa = if null fs then [] else map flagReader (splitOnElem ',' $ head fs)
-    in return (fn, fa)
+distroPkgArgReader :: ReadM (String, Version, String)
+distroPkgArgReader = let
+        readDistroPkg = do
+            (n, v) <- readPkgNVersion
+            char ','
+            r <- many (satisfy (/= ','))
+            return (n, v, r)
 
-strCblPkgArg :: Monad m => String -> m (String, String, FlagAssignment)
-strCblPkgArg s = let
-        flagReader ('-':cs) = (FlagName cs, False)
-        flagReader cs = (FlagName cs, True)
-        (vi:fs) = splitOnElem ':' s
-        fa = if null fs then [] else map flagReader (splitOnElem ',' $ head fs)
     in do
-        (pkgName, version) <- strPairArg ',' vi
-        if null fs
-            then do
-                (pkgName, version) <- strPairArg ',' vi
-                return (pkgName, version, [])
-             else return (pkgName, version, fa)
+        s <- readerAsk
+        case lastMay (readP_to_S readDistroPkg s) of
+            Just (r, "") -> return r
+            _ -> fail $ "Cannot parse '" ++ s ++ "' as PKG,VER,REL"
 
+strCblFileArgReader :: ReadM (FilePath, FlagAssignment)
+strCblFileArgReader = let
+        readWithFlags = do
+            fn <- many $ satisfy (/= ':')
+            char ':'
+            fas <- sepBy readFlag (char ',')
+            return (fn, fas)
+
+        readWithoutFlags = do
+            fn <- many $ satisfy (/= ':')
+            return (fn, [])
+
+    in do
+        s <-readerAsk
+        case lastMay (readP_to_S (readWithFlags <++ readWithoutFlags) s) of
+            Just (r, "") -> return r
+            _ -> fail $ "Cannot parse '" ++ s ++ "' as FILE[:FLAG,-FLAG,..]"
+
+strCblPkgArgReader :: ReadM (String, Version, FlagAssignment)
+strCblPkgArgReader = let
+        readWithFlags = do
+            (n, v) <- readPkgNVersion
+            char ':'
+            fas <- sepBy readFlag (char ',')
+            return (n, v, fas)
+
+        readWithoutFlags = do
+            (n, v) <- readPkgNVersion
+            return (n, v, [])
+
+    in do
+        s <- readerAsk
+        case lastMay (readP_to_S (readWithFlags <++ readWithoutFlags) s) of
+            Just (r, "") -> return r
+            _ -> fail $ "Cannot parse: " ++ s
+
 -- Helper for grabbing things out of the options
 optGet :: MonadReader o m => (o -> s) -> m s
 optGet f = liftM f ask
@@ -142,7 +170,7 @@
     = CmdAdd
         { patchDir :: FilePath, ghcVer :: Version, cmdAddGhcPkgs :: [(String, Version)]
         , cmdAddDistroPkgs :: [(String, Version, String)], cmdAddFileCbls :: [(FilePath, FlagAssignment)]
-        , cmdAddCbls :: [(String, String, FlagAssignment)] }
+        , cmdAddCbls :: [(String, Version, FlagAssignment)] }
     | CmdBuildPkgs { pkgs :: [String] }
     | CmdBumpPkgs { inclusive :: Bool, pkgs :: [String] }
     | CmdSync { unused :: Bool }
@@ -151,7 +179,7 @@
         { listGhc :: Bool, listDistro :: Bool, noListRepo :: Bool
         , hackageFmt :: Bool, pkgs :: [String] }
     | CmdUpdates { idxStyle :: Bool }
-    | CmdUrls { pkgVers :: [(String, String)] }
+    | CmdUrls { pkgVers :: [(String, Version)] }
     | CmdPkgBuild { ghcVer :: Version, ghcRel :: Int, patchDir :: FilePath, pkgs :: [String] }
     | CmdConvertDb { inDbFile :: FilePath, outDbFile :: FilePath }
     | CmdRemovePkg { pkgs :: [String] }
@@ -196,7 +224,8 @@
 
 -- | Read in a Cabal file.
 readCabalFromFile = readCabal
-readCabalFromIdx ad pd (p, v) = readCabal ad pd (p ++ "," ++ v)
+readCabalFromIdx ad pd (p, v) = readCabal ad pd (p ++ "," ++ v')
+    where v' = display v
 
 readCabal :: FilePath -> FilePath -> String -> FilePath -> ErrorT String IO GenericPackageDescription
 readCabal appDir patchDir loc tmpDir = let
