diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,10 @@
 # Release history for koji-install
 
+## 0.3 (2021-12-03)
+- add `--list` command to list recent builds
+- fix bug in generating kojifiles url from short name
+- workarounds for rpmfusion's older koji not supporting patterns
+
 ## 0.2.0 (2021-12-03)
 - initial Hackage release
 - `--hub` to select hub
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -13,33 +13,32 @@
 Will download the latest build for your Fedora version,
 and try to install it.
 
-You can specify a different hub using `--hub`.
+You can specify a different Koji hub service with `--hub`.
 
 ### Selecting subpackages
 
-By default only installed subpackages are and downloaded and updated,
+By default only installed subpackages are downloaded and updated,
 but the following options change the behavior:
 
 `--all`: install all subpackages
 
 `--ask`: ask about each subpackage
 
-`--base-only`: only install base package
+`--base-only`: only install the base package
 
 `--exclude-devel`: skip devel subpackages
 
 ### Help
 ```shellsession
-$ koji-install
-Install latest build from Koji
+$ koji-install --help
+Download and install latest package build from Koji tag.
 
 Usage: koji-install [--version] [-n|--dry-run] [-D|--debug] [-H|--hub HUB]
                     [-P|--packages-url URL]
-                    [(-a|--all) | (-A|--ask) | (-b|--base-only) |
+                    [(-l|--list) | (-a|--all) | (-A|--ask) | (-b|--base-only) |
                       (-D|--exclude-devel)] [-d|--disttag DISTTAG]
                     [(-R|--nvr) | (-V|--nv)] PACKAGE
-  Download and install latest package build from Koji tag.
-  HUB = fedora, stream, mbox, rpmfusion, URL
+  HUB = fedora, stream, rpmfusion, or URL
 
 Available options:
   -h,--help                Show this help text
@@ -48,6 +47,7 @@
   -D,--debug               More detailed output
   -H,--hub HUB             KojiHub shortname or url [default: fedora]
   -P,--packages-url URL    KojiFiles packages url [default: fedora]
+  -l,--list                List builds
   -a,--all                 all subpackages
   -A,--ask                 ask for each subpackge
   -b,--base-only           only base package
diff --git a/koji-install.cabal b/koji-install.cabal
--- a/koji-install.cabal
+++ b/koji-install.cabal
@@ -1,10 +1,10 @@
 name:                koji-install
-version:             0.2.0
+version:             0.3
 synopsis:            CLI tool for installing rpms directly from Fedora Koji
 description:
         koji-install can install the latest koji build of a package locally.
-        By default it only downloads newer binaries of the subpackages
-        already installed, but there are options to override that.
+        By default it only downloads newer binaries of already-installed
+        subpackages, but there are options to override that.
 license:             BSD3
 license-file:        LICENSE
 author:              Jens Petersen <juhpetersen@gmail.com>
@@ -37,11 +37,12 @@
                        extra,
                        filepath,
                        koji >= 0.0.2,
-                       optparse-applicative,
                        rpm-nvr,
                        simple-cmd,
                        simple-cmd-args,
                        xdg-userdirs
+  if impl(ghc<8.4)
+       build-depends: http-common < 0.8.3.4
   default-language:    Haskell2010
   ghc-options:         -Wall -threaded
   if impl(ghc >= 8.0)
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -9,8 +9,6 @@
 import Data.RPM
 import Distribution.Koji
 import qualified Distribution.Koji.API as Koji
-import Options.Applicative (fullDesc, header, progDescDoc)
-import qualified Options.Applicative.Help.Pretty as P
 import SimpleCmd
 import SimpleCmdArgs
 import System.Directory
@@ -20,9 +18,15 @@
 import DownloadDir
 import Paths_koji_install (version)
 
+-- FIXME use subtype for listing vs installation
+data Mode = List | InstMode InstallMode
+  deriving Eq
+
 data InstallMode = Update | All | Ask | Base | NoDevel
+  deriving Eq
 
 data Request = ReqName | ReqNV | ReqNVR
+  deriving Eq
 
 -- FIXME --include devel, --exclude *
 -- FIXME specify tag or task
@@ -33,13 +37,12 @@
 
 main :: IO ()
 main = do
-  sysdisttag <- cmd "rpm" ["--eval", "%{dist}"]
-  let pdoc = Just $ P.vcat
-             [ P.text "Download and install latest package build from Koji tag.",
-               P.text ("HUB = " <> intercalate ", " knownHubs)
-             ]
-  simpleCmdArgsWithMods (Just Paths_koji_install.version)
-    (fullDesc <> header "Install latest build from Koji" <> progDescDoc pdoc) $
+  sysdisttag <- do
+    dist <- cmd "rpm" ["--eval", "%{dist}"]
+    return $ if dist == "%{dist}" then "" else dist
+  simpleCmdArgs (Just Paths_koji_install.version)
+    "Download and install latest package build from Koji tag."
+    ("HUB = " ++ intercalate ", " knownHubs) $
     program
     <$> switchWith 'n' "dry-run" "Don't actually download anything"
     <*> switchWith 'D' "debug" "More detailed output"
@@ -53,13 +56,15 @@
          <|> flagWith ReqName ReqNVR 'V' "nv" "Give an N-V instead of package name")
     <*> some (strArg "PACKAGE")
   where
-    modeOpt :: Parser InstallMode
+    modeOpt :: Parser Mode
     modeOpt =
-      flagWith' All 'a' "all" "all subpackages" <|>
+      flagWith' List 'l' "list" "List builds" <|>
+      InstMode <$>
+      (flagWith' All 'a' "all" "all subpackages" <|>
       flagWith' Ask 'A' "ask" "ask for each subpackge" <|>
       flagWith' Base 'b' "base-only" "only base package" <|>
       flagWith' NoDevel 'D' "exclude-devel" "Skip devel packages" <|>
-      pure Update
+      pure Update)
 
     disttagOpt :: String -> Parser String
     disttagOpt disttag = startingDot <$> strOptionalWith 'd' "disttag" "DISTTAG" ("Use a different disttag [default: " ++ disttag ++ "]") disttag
@@ -69,14 +74,15 @@
         "" -> error' "empty disttag"
         (c:_) -> if c == '.' then cs else '.' : cs
 
+-- mbox kojihub is locked
 knownHubs :: [String]
-knownHubs = ["fedora","stream","mbox","rpmfusion", "URL"]
+knownHubs = ["fedora","stream","rpmfusion", "or URL"]
 
 hubURL :: String -> String
 hubURL "fedora" = fedoraKojiHub
 -- later use centosKojiHub
 hubURL "stream" = "https://kojihub.stream.centos.org/kojihub"
-hubURL "mbox" = "https://koji.mbox.centos.org/kojihub"
+--hubURL "mbox" = "https://koji.mbox.centos.org/kojihub"
 hubURL "rpmfusion" = "https://koji.rpmfusion.org/kojihub"
 hubURL "fusion" = "https://koji.rpmfusion.org/kojihub"
 hubURL hub =
@@ -84,23 +90,23 @@
   then hub
   else error' $ "unknown hub: try " ++ show knownHubs
 
-defaultPkgsURL :: Maybe String -> String
-defaultPkgsURL Nothing =
-  "https://kojipkgs.fedoraproject.org/packages"
-defaultPkgsURL (Just url) =
-  case url of
+defaultPkgsURL :: String -> String
+defaultPkgsURL url =
+  case dropSuffix "/" url of
+    "https://koji.fedoraproject.org/kojihub" ->
+      "https://kojipkgs.fedoraproject.org/packages"
     "https://kojihub.stream.centos.org/kojihub" ->
       "https://kojihub.stream.centos.org/kojifiles/packages"
     _ ->
       if "kojihub" `isSuffixOf` url
       then replace "kojihub" "kojifiles" url
-      else error' "use --files-url to specify kojifiles url for this kojihub"
+      else error' $ "use --files-url to specify kojifiles url for " ++ url
 
-program :: Bool -> Bool -> Maybe String -> Maybe String -> InstallMode
+program :: Bool -> Bool -> Maybe String -> Maybe String -> Mode
         -> String -> Request -> [String] -> IO ()
 program dryrun debug mhuburl mpkgsurl mode disttag request pkgs = do
   let huburl = maybe fedoraKojiHub hubURL mhuburl
-      pkgsurl = fromMaybe (defaultPkgsURL mhuburl) mpkgsurl
+      pkgsurl = fromMaybe (defaultPkgsURL huburl) mpkgsurl
   when debug $ do
     putStrLn huburl
     putStrLn pkgsurl
@@ -109,22 +115,29 @@
   when debug $ putStrLn dlDir
   setNoBuffering
   mapM (kojiLatestRPMs huburl pkgsurl dlDir) pkgs
-    >>= installRPMs dryrun . mconcat
+    >>= case mode of
+          List -> mapM_ putStrLn . mconcat
+          _ -> installRPMs dryrun . mconcat
   where
     kojiLatestRPMs :: String -> String -> String -> String -> IO [String]
     kojiLatestRPMs huburl pkgsurl dlDir pkg = do
-      mnvr <- kojiLatestOSBuild huburl disttag request pkg
-      case mnvr of
-        Nothing -> error' $ "latest " ++ pkg ++ " not found"
-        Just nvr -> do
-          putStrLn $ nvr ++ "\n"
-          allRpms <- map (<.> "rpm") . sort . filter (not . debugPkg) <$> kojiGetBuildRPMs huburl nvr
-          dlRpms <- decideRpms mode allRpms
-          unless (dryrun || null dlRpms) $ do
-            mapM_ (downloadRpm pkgsurl (readNVR nvr)) dlRpms
-            -- FIXME once we check file size - can skip if no downloads
-            putStrLn $ "Packages downloaded to " ++ dlDir
-          return dlRpms
+      nvrs <- kojiLatestOSBuilds debug huburl (mode == List) disttag request pkg
+      case mode of
+        List -> return nvrs
+        InstMode instmode ->
+          case nvrs of
+            [] -> error' $ "latest " ++ pkg ++ " not found for " ++ disttag
+            [nvr] -> do
+              putStrLn $ nvr ++ "\n"
+              allRpms <- map (<.> "rpm") . sort . filter (not . debugPkg) <$> kojiGetBuildRPMs huburl nvr
+              dlRpms <- decideRpms instmode allRpms
+              unless (dryrun || null dlRpms) $ do
+                mapM_ (downloadRpm pkgsurl (readNVR nvr)) dlRpms
+                -- FIXME once we check file size - can skip if no downloads
+                putStrLn $ "Packages downloaded to " ++ dlDir
+              return dlRpms
+            _ -> error $ "multiple latest build founds for " ++ pkg ++ ": " ++
+                 unwords nvrs
       where
         decideRpms :: InstallMode -> [String] -> IO [String]
         decideRpms mode' allRpms =
@@ -155,23 +168,39 @@
     debugPkg :: String -> Bool
     debugPkg p = "-debuginfo-" `isInfixOf` p || "-debugsource-" `isInfixOf` p
 
-kojiLatestOSBuild :: String -> String -> Request -> String -> IO (Maybe String)
-kojiLatestOSBuild hub disttag request pkgpat = do
+kojiLatestOSBuilds :: Bool -> String -> Bool -> String -> Request -> String
+                  -> IO [String]
+kojiLatestOSBuilds debug hub listmode disttag request pkgpat = do
   let (pkg,full) = packageOfPattern pkgpat
+      oldkoji = "rpmfusion" `isInfixOf` hub
+  when (oldkoji && ("*" `isInfixOf` pkgpat || request /= ReqName)) $
+    error' "cannot use pattern with this kojihub"
   mpkgid <- Koji.getPackageID hub pkg
   case mpkgid of
     Nothing -> error $ "package not found: " ++ pkg
     Just pkgid -> do
-      let opts = [("packageID", ValueInt pkgid),
+      -- strictly should getAPIVersion
+      let opts = (if oldkoji
+                  then id
+                  else (("pattern", ValueString (if full then pkgpat else dropSuffix "*" pkgpat ++ "*" ++ disttag ++ "*")) :))
+                 [("packageID", ValueInt pkgid),
                   ("state", ValueInt (fromEnum BuildComplete)),
-                  ("queryOpts",ValueStruct [("limit",ValueInt 1),
-                                            ("order",ValueString "-build_id")])]
-      res <- Koji.listBuilds hub $
-             ("pattern", ValueString (if full then pkgpat else dropSuffix "*" pkgpat ++ "*" ++ disttag)) : opts
-      case res of
-        [] -> return Nothing
-        [bld] -> return $ lookupStruct "nvr" bld
-        _ -> error $ "more than one latest build found for " ++ pkg
+                  ("queryOpts",ValueStruct
+                    [("limit",ValueInt $ if listmode || oldkoji then 10 else 1),
+                     ("order",ValueString "-build_id")])]
+      when debug $ print opts
+      nvrs <- mapMaybe (lookupStruct "nvr") <$> Koji.listBuilds hub opts
+      if null nvrs
+        then error' $ "no builds found for " ++ disttag
+        else
+        return $
+        if oldkoji
+        then case filter (disttag `isInfixOf`) nvrs of
+               [] -> error' $ "no builds found for " ++ disttag
+               [res] -> [res]
+               rs@(r:_) ->
+                 if listmode then rs else [r]
+        else nvrs
   where
     packageOfPattern :: String -> (String, Bool)
     packageOfPattern pat =
diff --git a/test/tests.hs b/test/tests.hs
--- a/test/tests.hs
+++ b/test/tests.hs
@@ -3,18 +3,28 @@
 
 program :: [String] -> IO ()
 program args =
-  putStrLn "" >> cmdLog "koji-install" ("-n" : "-b" : args)
+  putStrLn "" >>
+  cmdLog "koji-install" ("-n" : args)
 
-tests :: [[String]]
-tests =
-  [["podman"]
-  ,["-H", "https://kojihub.stream.centos.org/kojihub", "-d", "el9", "bash"]
-  ,["-H", "stream", "-d", "el9", "kernel"]
---  ,["-H", "rpmfusion", "ffmpeg"]
+tests :: Bool -> [[String]]
+tests havedist =
+  [["-b", "podman"] ++ sysdist
+  ,["-l", "coreutils"] ++ sysdist
+  ,["-b", "-H", "https://kojihub.stream.centos.org/kojihub", "-d", "el9", "bash"]
+  ,["-b", "-H", "stream", "-d", "el9", "kernel"]
+  ,["-l", "-H", "stream", "-d", "el9", "grep"]
+  ,["-b", "-H", "rpmfusion", "ffmpeg"] ++ sysdist
+  ,["-l", "-H", "rpmfusion", "ffmpeg"] ++ sysdist
   ]
+  where
+    sysdist = if havedist then [] else ["-d", "fc35"]
 
 main :: IO ()
 main = do
   hSetBuffering stdout NoBuffering
-  mapM_ program tests
-  putStrLn $ show (length tests) ++ " tests run"
+  havedist <- do
+    dist <- cmd "rpm" ["--eval", "%{dist}"]
+    return $ dist /= "%{dist}"
+  let cases = tests havedist
+  mapM_ program cases
+  putStrLn $ show (length cases) ++ " tests run"
