diff --git a/Version.hs b/Version.hs
--- a/Version.hs
+++ b/Version.hs
@@ -1,11 +1,13 @@
 -- boilerplate {{{
-module Version (CurrentFormat, parseCurrentFormat) where
+module Version (CurrentFormat, parseCurrentFormat, version) where
 import Data.Map (Map, elems, empty)
 import Data.Time (UTCTime, getCurrentTime)
 
 type CurrentFormat = FormatV2
-
+version            :: String
 parseCurrentFormat :: String -> IO CurrentFormat
+
+version            = "yeganesh version 2.1"
 parseCurrentFormat = parseFormatV2
 -- }}}
 -- v2 {{{
diff --git a/yeganesh.cabal b/yeganesh.cabal
--- a/yeganesh.cabal
+++ b/yeganesh.cabal
@@ -1,5 +1,5 @@
 name:               yeganesh
-version:            2.0
+version:            2.1
 cabal-version:      >=1.2
 build-type:         Simple
 license:            BSD3
diff --git a/yeganesh.hs b/yeganesh.hs
--- a/yeganesh.hs
+++ b/yeganesh.hs
@@ -8,26 +8,47 @@
 import Data.Map (Map, insert, findWithDefault, fromList, toList, union)
 import Data.Ord (comparing)
 import Data.Time (UTCTime, diffUTCTime, getCurrentTime)
-import System.Console.GetOpt (ArgDescr(ReqArg), ArgOrder(RequireOrder), OptDescr(Option), getOpt)
+import System.Console.GetOpt (ArgDescr(NoArg, ReqArg), ArgOrder(RequireOrder), OptDescr(Option), getOpt, usageInfo)
 import System.Directory (createDirectoryIfMissing)
 import System.Environment (getArgs, getEnv)
 import System.FilePath ((</>))
-import System.IO (hClose, hGetContents, hPutStr, hPutStrLn, stderr, stdout)
+import System.IO (hClose, hGetContents, hPutStr, stderr, stdout)
 import System.Process (runInteractiveProcess, waitForProcess)
-import Version (CurrentFormat, parseCurrentFormat)
+import Version (CurrentFormat, parseCurrentFormat, version)
 import qualified System.IO.Strict as Strict (getContents, readFile)
 -- }}}
 -- getopt {{{
-options :: [OptDescr String]
-options = [Option "p" ["profile"] (ReqArg id "PROFILE") "which popularity profile to use"]
+options :: [OptDescr Flag]
+options =   [Option "p" ["profile"] (ReqArg Profile "PROFILE") "which popularity profile to use"
+            ,Option "v" ["version"] (NoArg Version)            "print the version number"
+            ,Option "h" ["help"   ] (NoArg Help)               "show usage information"
+            ]
 
-data Options = Options { dmenuOpts :: [String], profile :: String } deriving Show
+data Options = Options { dmenuOpts :: [String], profile :: String }
+data Flag    = Profile String | Version | Help
 
+compactFlags :: [Flag] -> Flag
+compactFlags = foldr1 compactFlags' . (Profile "default" :) where
+    compactFlags' Help    _ = Help
+    compactFlags' _    Help = Help
+    compactFlags' Version _ = Version
+    compactFlags' _ Version = Version
+    compactFlags' _ p       = p
+
+introText :: String
+introText = unlines $ [
+    version,
+    "Usage: yeganesh [OPTIONS] -- [DMENU_OPTIONS]",
+    "OPTIONS are described below, and DMENU_OPTIONS are passed on verbatim to dmenu.",
+    "Profiles are stored in the $HOME/.yeganesh directory."]
+
 parseOptions :: [String] -> Either String Options
 parseOptions ss = fmap (Options dOpts) p where
     (opts, dOpts) = fmap (drop 1) . break (== "--") $ ss
-    p = case getOpt RequireOrder options opts of
-        (ps, [], []) -> Right . last $ "default" : ps
+    p = case onFirst compactFlags $ getOpt RequireOrder options opts of
+        (Profile f, [], []) -> Right f
+        (Version  , [], []) -> Left version
+        (Help     , [], []) -> Left $ usageInfo introText options
         (_ , ns, []) -> Left $ "Unknown options: " ++ unwords ns
         (_ , _ , es) -> Left  . concat $ es
 -- }}}
@@ -44,6 +65,9 @@
 readPossiblyNonExistent file = catch (Strict.readFile file) (const . return $ "") >>= parseCurrentFormat
 -- }}}
 -- pure {{{
+onFirst :: (a -> a') -> (a, b, c) -> (a', b, c)
+onFirst f (a, b, c) = (f a, b, c)
+
 sortOn :: Ord b => (a -> b) -> [a] -> [a]
 sortOn f = map snd . sortBy (comparing fst) . map (f &&& id)
 
@@ -54,6 +78,9 @@
 showPriority = unlines . map fst . sortOn descSnd . toList
 
 -- decay exponentially, with a one-month half-life
+-- The key for decay is that it be monotonic, so that commands will appear in
+-- the same order before and after a decay operation; this means we can delay
+-- the decay until *after* the user has selected an option.
 decay :: UTCTime -> UTCTime -> Commands -> Commands
 decay old new = fmap (/factor) where
     seconds = fromRational . toRational $ diffUTCTime new old
@@ -86,7 +113,7 @@
 dmenu :: [String] -> CurrentFormat -> IO CurrentFormat
 dmenu opts cv@(_, cmds) = do
     (hIn, hOut, hErr, p) <- runInteractiveProcess "dmenu" opts Nothing Nothing
-    hPutStrLn hIn (showPriority cmds)
+    hPutStr hIn (showPriority cmds)
     hClose hIn
     o <- hGetContents hOut
     e <- hGetContents hErr
