diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -73,4 +73,15 @@
 	* add password manager
 
 0.5.1.1 Chris Dornan <chrisd@irisconnect.co.uk> 2014-09-08
-	* fixsetEnv usage to work with GHCs 7.6.3 & 7.8.3
+	* fix setEnv usage to work with GHCs 7.6.3 & 7.8.3
+
+0.6.0.0 Chris Dornan <chrisd@irisconnect.co.uk> 2014-09-21
+	* add dynamic passwords to the passowrd manager
+	* add password manager importing
+	* fix bugs in the PasswordManager `amLoggedIn` and `passwordValid`
+	  (they were throwing exceptions rather than returning False)
+	* add support for shell prompts to the password manager
+	* expose the optparse-applicative PasswordManager CLI parser and abstract
+	  syntax for cleaner embedding in optparse-applicative parsers
+    * hope dependent pacakges have stopped breaking the Hackage build
+
diff --git a/examples/deploy/deploy.hs b/examples/deploy/deploy.hs
--- a/examples/deploy/deploy.hs
+++ b/examples/deploy/deploy.hs
@@ -15,8 +15,10 @@
 import qualified Data.ByteString.Lazy.Char8     as LBS
 import qualified Data.Text                      as T
 import qualified Data.Text.IO                   as T
+import           Data.List
 import           System.IO
 import           System.Environment
+import           System.SetEnv
 import           System.Process
 import           Control.Applicative
 import           Control.Exception
@@ -38,6 +40,7 @@
     , _pmc_allow_dumps    = True
     , _pmc_dump_prefix    = dump_pfx
     , _pmc_sample_script  = Just $ defaultSampleScript (PW_ :: PW_ SectionID) dump_pfx
+    , _pmc_plus_env_var   = \(PasswordName nm) -> Just $ EnvVar $ T.concat ["DEPLOY_PW_",nm]
     }
   where
     dump_pfx = "deploy pm"
@@ -117,7 +120,11 @@
 interactive_shell = do
   sh <- maybe "/bin/bash" id <$> lookupEnv "SHELL"
   putStrLn $ "launching password-manager shell => " ++ sh
-  callProcess sh ["-i"]
+  case "zsh" `isInfixOf` sh of
+    True  -> do
+      setEnv "ZDOTDIR" "examples/deploy/zshenv"
+      callProcess sh ["-i"]
+    False -> callProcess sh ["-i"]
   putStrLn "password-manager shell done"
 
 write :: Maybe FilePath -> LBS.ByteString -> IO ()
diff --git a/examples/deploy/example-pwstore.dat b/examples/deploy/example-pwstore.dat
new file mode 100644
Binary files /dev/null and b/examples/deploy/example-pwstore.dat differ
diff --git a/examples/deploy/zshenv/.zshrc b/examples/deploy/zshenv/.zshrc
new file mode 100644
--- /dev/null
+++ b/examples/deploy/zshenv/.zshrc
@@ -0,0 +1,6 @@
+source "${HOME}/.zshrc"
+
+if (( $+commands[deploy] )) ; then
+  setopt PROMPT_SUBST
+  PS1='%{$fg_bold[green]%}$(deploy pm prompt)$fg_bold[blue]%} ➜ %{$reset_color%}'
+fi
diff --git a/keystore.cabal b/keystore.cabal
--- a/keystore.cabal
+++ b/keystore.cabal
@@ -1,5 +1,5 @@
 Name:                   keystore
-Version:                0.5.1.1
+Version:                0.6.0.0
 Synopsis:               Managing stores of secret things
 Homepage:               http://github.com/cdornan/keystore
 Author:                 Chris Dornan
@@ -120,7 +120,13 @@
   .
   See the bottom <https://github.com/cdornan/keystore#launch-instructions README>
   on GitHub home page for launch instructions for the deploy example.
+Data-files:
+    keystore.manifest
+    keystore783.manifest
+    examples/deploy/zshenv/.zshrc
+    examples/deploy/example-pwstore.dat
 
+
 Extra-source-files:     changelog
 Cabal-version:          >= 1.14
 
@@ -235,9 +241,9 @@
         optparse-applicative   >= 0.9.0             ,
         process                >= 1.2.0.0           ,
         raw-strings-qq         >= 1.0.2             ,
+        setenv                 >= 0.1               ,
         text                   >= 0.11              ,
         unordered-containers   >= 0.2.3.0
-
 
     GHC-Options:
         -Wall -fno-warn-warnings-deprecations
diff --git a/keystore.manifest b/keystore.manifest
new file mode 100644
--- /dev/null
+++ b/keystore.manifest
@@ -0,0 +1,73 @@
+^=7.6.3
+Cabal-1.20.0.2
+MonadCatchIO-transformers-0.3.0.0
+QuickCheck-2.7.3
+aeson-0.6.2.1
+aeson-pretty-0.7
+ansi-terminal-0.6.1.1
+ansi-wl-pprint-0.6.7.1
+api-tools-0.4
+api-tools-0.4.0.1
+asn1-encoding-0.8.1.3
+asn1-types-0.2.3
+attoparsec-0.11.2.1
+base64-bytestring-1.0.0.1
+bifunctors-4.1.1.1
+blaze-builder-0.3.3.2
+byteable-0.1.1
+bytedump-1.0
+case-insensitive-1.1.0.3
+cereal-0.4.0.1
+cipher-aes-0.2.6
+cmdargs-0.10.7
+comonad-4.2
+contravariant-0.6
+crypto-cipher-types-0.0.9
+crypto-numbers-0.2.3
+crypto-pubkey-0.2.4
+crypto-pubkey-types-0.4.1
+crypto-random-0.0.7
+cryptohash-0.11.2
+distributive-0.4.4
+dlist-0.6.0.1
+extensible-exceptions-0.1.1.4
+generic-deriving-1.6.2
+hashable-1.2.1.0
+keystore-0.5.0.2
+keystore-0.5.0.3
+keystore-0.5.1.0
+lens-3.10.2
+mtl-2.1.3.1
+nats-0.1.2
+optparse-applicative-0.9.0
+optparse-applicative-0.9.1.1
+parallel-3.2.0.4
+parsec-3.1.5
+pbkdf-1.1.1.1
+primitive-0.5.2.1
+process-1.2.0.0
+profunctors-4.0.4
+random-1.0.1.1
+raw-strings-qq-1.0.2
+reflection-1.3.2
+regex-base-0.93.2
+regex-compat-tdfa-0.95.1.4
+regex-tdfa-1.2.0
+safe-0.3.3
+safecopy-0.8.2
+scientific-0.2.0.2
+securemem-0.1.3
+semigroupoids-4.0.2.1
+semigroups-0.12.2
+setenv-0.1.1.1
+split-0.2.2
+syb-0.4.1
+tagged-0.7
+text-1.1.0.1
+tf-random-0.4
+transformers-0.3.0.0
+transformers-compat-0.3.3.4
+unordered-containers-0.2.3.3
+utf8-string-0.3.7
+vector-0.10.9.1
+void-0.6.1
diff --git a/keystore783.manifest b/keystore783.manifest
new file mode 100644
--- /dev/null
+++ b/keystore783.manifest
@@ -0,0 +1,67 @@
+^=7.8.3
+QuickCheck-2.7.6
+aeson-0.8.0.0
+aeson-pretty-0.7.1
+ansi-terminal-0.6.1.1
+ansi-wl-pprint-0.6.7.1
+api-tools-0.4.0.1
+asn1-encoding-0.8.1.3
+asn1-types-0.2.3
+attoparsec-0.12.1.1
+base64-bytestring-1.0.0.1
+bifunctors-4.1.1.1
+byteable-0.1.1
+bytedump-1.0
+case-insensitive-1.2.0.0
+cereal-0.4.0.1
+cipher-aes-0.2.8
+cmdargs-0.10.9
+comonad-4.2.2
+contravariant-1.2
+crypto-cipher-types-0.0.9
+crypto-numbers-0.2.3
+crypto-pubkey-0.2.4
+crypto-pubkey-types-0.4.2.2
+crypto-random-0.0.8
+cryptohash-0.11.6
+distributive-0.4.4
+dlist-0.7.1
+exceptions-0.6.1
+free-4.9
+hashable-1.2.2.0
+keystore-0.5.1.0
+lens-4.3.3
+mtl-2.2.1
+nats-0.2
+optparse-applicative-0.9.1.1
+parallel-3.2.0.4
+parsec-3.1.5
+pbkdf-1.1.1.1
+prelude-extras-0.4
+primitive-0.5.3.0
+profunctors-4.2.0.1
+random-1.0.1.3
+raw-strings-qq-1.0.2
+reflection-1.5.1
+regex-base-0.93.2
+regex-compat-tdfa-0.95.1.4
+regex-tdfa-1.2.0
+safe-0.3.8
+safecopy-0.8.3
+scientific-0.3.3.0
+securemem-0.1.3
+semigroupoids-4.2
+semigroups-0.15.2
+setenv-0.1.1.1
+split-0.2.2
+syb-0.4.2
+tagged-0.7.2
+text-1.1.1.3
+tf-random-0.5
+transformers-0.4.1.0
+transformers-compat-0.3.3.4
+unordered-containers-0.2.5.0
+utf8-string-0.3.8
+vector-0.10.11.0
+void-0.6.1
+zlib-0.5.4.1
diff --git a/src/Data/KeyStore/PasswordManager.hs b/src/Data/KeyStore/PasswordManager.hs
--- a/src/Data/KeyStore/PasswordManager.hs
+++ b/src/Data/KeyStore/PasswordManager.hs
@@ -21,23 +21,35 @@
     , bindMasterPassword
     , setup
     , passwordValid
+    , passwordValid'
     , isStorePresent
     , amLoggedIn
     , isBound
+    , import_
     , load
+    , loadPlus
     , psComment
     , collect
     , prime
     , select
     , deletePassword
+    , deletePasswordPlus
     , deleteSession
     , status
+    , prompt
     , passwords
+    , passwordsPlus
     , sessions
     , infoPassword
     , infoPassword_
+    , infoPasswordPlus
+    , infoPasswordPlus_
     , dump
     , collectShell
+    -- password manager CLI internals
+    , passwordManager'
+    , PMCommand
+    , parseCommand
     ) where
 
 import           Data.KeyStore.Types.PasswordStoreModel
@@ -92,6 +104,8 @@
     , _pmc_allow_dumps    :: Bool         -- ^ must be true to enable 'dump' commands
     , _pmc_dump_prefix    :: String       -- ^ the prefix string to be used in making up the commands from dump scripts
     , _pmc_sample_script  :: Maybe String -- ^ the sample script
+    , _pmc_plus_env_var   :: PasswordName -> Maybe EnvVar
+                                          -- ^ map the dynamic (plus) passwords to their environment variables
     }
 
 -- | The PW class provides all of the information on the bounded enumeration type used to identify the passwords
@@ -153,26 +167,7 @@
 
 -- | the password manager CLI: it just needs the config and command line
 passwordManager :: PW p => PMConfig p -> [String] -> IO ()
-passwordManager pmc args = do
-  pmcd <- parse_command pmc args
-  case pmcd of
-    PMCD_version                -> putStrLn version
-    PMCD_setup          nl mb_t -> setup          pmc nl mb_t
-    PMCD_login        y    mb_t -> login          pmc y  mb_t
-    PMCD_load            p mb_t -> load           pmc p  mb_t
-    PMCD_comment            cmt -> psComment      pmc cmt
-    PMCD_prime        u  p      -> prime          pmc u $ Just p
-    PMCD_prime_all    u         -> prime          pmc u Nothing
-    PMCD_select          mb snm -> select         pmc mb snm
-    PMCD_delete_password p      -> deletePassword pmc p
-    PMCD_delete_session  mb snm -> deleteSession  pmc mb snm
-    PMCD_status      q          -> status         pmc q
-    PMCD_passwords   b          -> passwords      pmc b
-    PMCD_sessions    a b mb     -> sessions       pmc a b mb
-    PMCD_info        s   p      -> infoPassword   pmc s p
-    PMCD_dump        s          -> dump           pmc s
-    PMCD_collect                -> collectShell   pmc
-    PMCD_sample_script          -> putStr $ maybe "" id $ _pmc_sample_script pmc
+passwordManager pmc args = parseCommand pmc args >>= passwordManager' pmc
 
 -- | a sample 'HashDescription' generator to help with setting up 'PMConfig'
 defaultHashDescription :: Salt -> HashDescription
@@ -218,9 +213,11 @@
     ex <- doesFileExist _pmc_location
     when ex $ error $ "password store already exists in: " ++ _pmc_location
     -- get a password from stdin if we have not been passed one
-    pwt <- maybe (get_pw pmc) return mb_pwt
+    pwt  <- maybe (get_pw True pmc) return mb_pwt
+    pwt' <- maybe (get_pw True pmc) return mb_pwt
+    when (pwt/=pwt') $ error "passwords do not match"
     -- need creation time and comment
-    now <- getCurrentTime
+    now  <- getCurrentTime
     let ps =
           PasswordStore
             { _ps_comment = PasswordStoreComment $ T.pack $ "Created at " ++ show now
@@ -239,7 +236,7 @@
 -- if no 'PasswordText' is specified then one will be read from stdin
 login :: PW p => PMConfig p -> Bool -> Maybe PasswordText -> IO ()
 login pmc y mb = do
-  pwt <- maybe (get_pw pmc) return mb
+  pwt <- maybe (get_pw True pmc) return mb
   ok  <- passwordValid pmc pwt
   case ok of
     True  -> bindMasterPassword pmc pwt >> good >> _pmc_shell pmc
@@ -251,15 +248,23 @@
 
 -- | is this the correct master password?
 passwordValid :: PW p => PMConfig p -> PasswordText -> IO Bool
-passwordValid pmc = password_valid pmc . mk_aek
+passwordValid pmc pwt = isJust <$> passwordValid' pmc (_pmc_location pmc) pwt
 
+-- | is this the correct master password for this keystore? Return the decrypted
+-- keystore if so.
+passwordValid' :: PW p => PMConfig p -> FilePath -> PasswordText -> IO (Maybe PasswordStore)
+passwordValid' pmc fp = password_valid pmc fp . mk_aek
+
 -- | is the password store there?
 isStorePresent :: PW p => PMConfig p -> IO Bool
 isStorePresent PMConfig{..} = doesFileExist _pmc_location
 
 -- | are we currently logged in?
 amLoggedIn :: PW p => PMConfig p -> IO Bool
-amLoggedIn pmc = get_key pmc >>= password_valid pmc
+amLoggedIn pmc = flip catch hdl $
+    isJust <$> (get_key pmc >>= password_valid pmc (_pmc_location pmc))
+  where
+    hdl (_::SomeException) = return False
 
 -- | is the password/session bound to a value in the store?
 isBound :: PW p => PMConfig p -> p -> Maybe SessionName -> IO Bool
@@ -268,12 +273,21 @@
     Nothing           -> False
     Just Password{..} -> maybe True (\snm->Map.member snm $ _pw_sessions) mb
 
+-- | import the contents of another keystore into the current keystore
+import_ :: PW p => PMConfig p -> FilePath -> Maybe PasswordText -> IO ()
+import_ pmc fp mb = wrap pmc $ \ps -> do
+  pwt   <- maybe (get_pw True pmc) return mb
+  mb_ps <- passwordValid' pmc fp pwt
+  case mb_ps of
+    Nothing  -> error "*** Password Invalid ***\n"
+    Just ps' -> return $ Just $ merge_ps ps ps'
+
 -- | loads a password into the store; if this is a session password and the
 -- boolean ss is True then the session will be reset to this password also;
 -- if no 'PasswordText' is specified then one will be read from stdin
 load :: PW p => PMConfig p -> p -> Maybe PasswordText -> IO ()
 load pmc p mb = wrap pmc $ \ps -> do
-  pwt <- maybe (get_pw pmc) return mb
+  pwt <- maybe (get_pw False pmc) return mb
   now <- getCurrentTime
   case isSession p of
     Nothing  -> load_pwd ps
@@ -322,6 +336,24 @@
 
     pnm             = pwName p
 
+-- | load a dynamic password into the Password store
+loadPlus :: PW p => PMConfig p -> PasswordName -> Maybe PasswordText -> IO ()
+loadPlus pmc pnm_ mb = wrap pmc $ \ps -> do
+  pwt <- maybe (get_pw False pmc) return mb
+  now <- getCurrentTime
+  load_pwd ps
+      Password
+        { _pw_name      = pnm
+        , _pw_text      = pwt
+        , _pw_sessions  = Map.empty
+        , _pw_isOneShot = False
+        , _pw_primed    = False
+        , _pw_setup     = now
+        }
+  where
+    pnm             = PasswordName $ (T.cons '+') $ _PasswordName pnm_
+    load_pwd ps pw  = return $ Just $ L.over ps_map (Map.insert pnm pw) ps
+
 -- | set the comment for the password store
 psComment :: PW p => PMConfig p -> PasswordStoreComment -> IO ()
 psComment pmc cmt = wrap pmc $ \ps -> return $ Just $ L.set ps_comment cmt ps
@@ -330,8 +362,15 @@
 -- and bind them in their designated environmants variables
 collect :: PW p => PMConfig p -> CollectConfig p -> IO ()
 collect pmc CollectConfig{..} = wrap_ pmc $ \ps -> do
-    -- set up the environment
+    -- set up the environment -- first the static passwords...
     mapM_ (clct pmc ps) _cc_active
+    -- ... then the dynamic (+) passwords
+    sequence_
+      [ set_env ev $ _pw_text pw
+        | (pnm_,pw) <- Map.toList $ _ps_map ps
+        , Just pnm  <- [is_plus pnm_]
+        , Just ev   <- [_pmc_plus_env_var pmc pnm]
+        ]
     -- now clear down all of the primed passwords
     return $ Just $ L.over ps_map (Map.map (L.set pw_primed False)) ps
   where
@@ -364,6 +403,10 @@
 deletePassword :: PW p => PMConfig p -> p -> IO ()
 deletePassword pmc p = wrap pmc $ \ps -> return $ Just $ L.over ps_map (Map.delete (pwName p)) ps
 
+-- | delete a password from the store
+deletePasswordPlus :: PW p => PMConfig p -> PasswordName -> IO ()
+deletePasswordPlus pmc pnm = wrap pmc $ \ps -> return $ Just $ L.over ps_map (Map.delete (plussify pnm)) ps
+
 -- | delete a session from the store
 deleteSession :: PW p => PMConfig p -> Maybe p -> SessionName -> IO ()
 deleteSession pmc mb snm = wrap pmc $ \ps -> do
@@ -380,7 +423,6 @@
 
     f   ps (p,pw,_) = Just $ L.over ps_map (Map.insert (pwName p) (L.over pw_sessions (Map.delete snm) pw)) ps
 
-
 -- | print a status line; if @q@ is @True@ then don't output anything and exit
 -- with fail code 1 if not logged in
 status :: PW p => PMConfig p -> Bool -> IO ()
@@ -415,6 +457,28 @@
 
     hdl (_::SomeException) = exitWith $ ExitFailure 1
 
+-- | print a status apropriate for a prompt
+prompt :: PW p => PMConfig p -> IO ()
+prompt pmc = flip catch hdl $ do
+  li <- amLoggedIn pmc
+  case li of
+    True  -> enquire pmc line
+    False -> putStrLn "*"
+  where
+    line ps = putStrLn $ "[" ++ unwords sns ++ "]"
+      where
+        sns =
+          [ T.unpack $ _SessionName $ _sd_name sd
+            | pw <- Map.elems $ _ps_map ps
+            , let Password{..} = pw
+            , Just  p   <- [parsePwName _pw_name]
+            , Just  prs <- [isSession $ cast_pmc pmc p]
+            , Right sd  <- [prs _pw_text]
+            , is_primed pw
+            ]
+
+    hdl (_::SomeException) = putStrLn "???"
+
 -- | list the passwords, one per line; if @a@ is set then all passwords will be listed,
 -- otherwise just the primed passwords will be listed
 passwords :: PW p => PMConfig p -> Bool -> IO ()
@@ -445,6 +509,27 @@
         , Just pwd <- [Map.lookup (pwName p) $ _ps_map ps]
         ]
 
+-- | list all of the dynamic (+) passwords
+passwordsPlus :: PW p => PMConfig p -> Bool -> IO ()
+passwordsPlus pmc br = do
+  tz <- getCurrentTimeZone
+  enquire pmc $ \ps ->
+    putStr $ unlines $ map (fmt tz) $ pws ps
+  where
+    fmt tz (pnm,Password{..})
+        | br        = nm_s
+        | otherwise = printf "+%-12s $%-18s %s" nm_s ev_s su_s
+      where
+        nm_s = T.unpack $ _PasswordName pnm
+        ev_s = T.unpack $ _EnvVar $ fromMaybe "?" $ _pmc_plus_env_var pmc pnm
+        su_s = pretty_setup tz _pw_setup
+
+    pws ps =
+      [ (pnm,pw)
+        | (pnm_,pw) <- Map.toList $ _ps_map ps
+        , Just pnm  <- [is_plus pnm_]
+        ]
+
 -- | list the sessions, one per line; if @p@ is specified then all of the
 -- sessions are listed for that password
 sessions :: PW p
@@ -492,17 +577,17 @@
 -- | get the info on a password
 infoPassword_ :: PW p => PMConfig p -> Bool -> p -> IO P.Doc
 infoPassword_ pmc sh_s p = do
-  tz <- getCurrentTimeZone
-  enquire pmc $ \ps ->
-    return $ maybe P.empty (mk tz) $ Map.lookup pnm $ _ps_map ps
+    tz <- getCurrentTimeZone
+    enquire pmc $ \ps ->
+      return $ maybe P.empty (mk tz) $ Map.lookup pnm $ _ps_map ps
   where
     mk tz pw@Password{..} =
         heading           P.<$$> P.indent 4 (
             sssions       P.<>
             primed        P.<$$>
             evar          P.<$$>
-            loaded        P.<$$>
             secret        P.<>
+            loaded        P.<$$>
             P.empty       P.<$$>
             descr
           )               P.<$$>
@@ -536,6 +621,42 @@
 
     ljust n s = s ++ replicate (max 0 (n-length s)) ' '
 
+-- | print the info for a dynamic (+) password
+infoPasswordPlus :: PW p => PMConfig p -> Bool -> PasswordName -> IO ()
+infoPasswordPlus pmc sh_s pnm = do
+  doc <- infoPasswordPlus_ pmc sh_s pnm
+  putStr $ P.displayS (P.renderPretty 0.75 120 doc) ""
+
+-- | get the info on a dynamic (+) password
+infoPasswordPlus_ :: PW p => PMConfig p -> Bool -> PasswordName -> IO P.Doc
+infoPasswordPlus_ pmc sh_s pnm = do
+    tz <- getCurrentTimeZone
+    enquire pmc $ \ps ->
+      return $ maybe P.empty (mk tz) $ Map.lookup (plussify pnm) $ _ps_map ps
+  where
+    mk tz Password{..} =
+        heading           P.<$$> P.indent 4 (
+          evar          P.<>
+          secret        P.<>
+          loaded
+          )             P.<$$>
+          P.empty
+      where
+        heading  = P.bold $ P.string $ "+" ++ T.unpack (_PasswordName pnm)
+        evar     = case _pmc_plus_env_var pmc pnm of
+          Nothing -> P.empty
+          Just ev -> (line "env var" $ T.unpack $ _EnvVar $ ev          ) P.<$$> P.empty
+        loaded     =  line "loaded"  $ pretty_setup tz $ _pw_setup
+        secret   = case sh_s of
+          True  ->   (line "secret"  $ T.unpack $ _PasswordText _pw_text) P.<$$> P.empty
+          False -> P.empty
+
+        line :: String -> String -> P.Doc
+        line nm vl = P.bold(P.string $ ljust 8 nm) P.<> P.string " : " P.<>
+                                                        P.hang 8 (P.string vl)
+
+    ljust n s = s ++ replicate (max 0 (n-length s)) ' '
+
 -- | dump the store in a s script that can be used to reload it
 dump :: PW p => PMConfig p -> Bool -> IO ()
 dump pmc inc_ssns = enquire pmc dmp >> prime pmc True Nothing
@@ -603,16 +724,20 @@
     ]
 
 -- | read a passord from stdin and hash it
-get_pw :: PW p => PMConfig p -> IO PasswordText
-get_pw pmc = do
+get_pw :: PW p => Bool -> PMConfig p -> IO PasswordText
+get_pw hp pmc = do
   hSetEcho stdin False
   putStr "Password: "
   hFlush stdout
   pw <- getLine
   putChar '\n'
   hSetEcho stdin True
-  return $ hashMasterPassword pmc pw
+  return $ cond_hash hp pmc pw
 
+cond_hash :: PW p => Bool -> PMConfig p -> String -> PasswordText
+cond_hash False _   = PasswordText . T.pack
+cond_hash True  pmc = hashMasterPassword pmc
+
 -- | use a '+' to represent a primed one-shot password,'-' otherwise
 prime_char :: Bool -> Char
 prime_char is_p = if is_p then '+' else '-'
@@ -664,15 +789,18 @@
   aek <- get_key pmc
   load_ps pmc aek >>= f
 
-password_valid :: PW p => PMConfig p -> AESKey -> IO Bool
-password_valid pmc aek = catch ld hd
+password_valid :: PW p => PMConfig p -> FilePath -> AESKey -> IO (Maybe PasswordStore)
+password_valid pmc fp aek = catch ld hd
   where
-    ld                    = const True <$> load_ps pmc aek
-    hd (_::SomeException) = return False
+    ld                    = Just <$> load_ps_ pmc fp aek
+    hd (_::SomeException) = return Nothing
 
 load_ps :: PW p => PMConfig p -> AESKey -> IO PasswordStore
-load_ps pmc aek = do
-  aed <- load_ps' pmc
+load_ps pmc = load_ps_ pmc (_pmc_location pmc)
+
+load_ps_ :: PW p => PMConfig p -> FilePath -> AESKey -> IO PasswordStore
+load_ps_ pmc fp aek = do
+  aed <- load_ps' pmc fp
   case decodeWithErrs $ BL.fromChunks [_Binary $ _ClearText $ decryptAES aek aed] of
     Right pws -> return pws
     Left  ers -> error $ prettyJSONErrorPositions ers
@@ -682,9 +810,9 @@
   iv <- random_bytes sizeAesIV IV
   save_ps' pmc $ encryptAES aek iv $ ClearText $ Binary $ BL.toStrict $ A.encode pws
 
-load_ps' :: PW p => PMConfig p -> IO AESSecretData
-load_ps' PMConfig{..} = flip catch hdl $ do
-  (iv,ct) <- B.splitAt (_Octets sizeAesIV) <$> B.readFile _pmc_location
+load_ps' :: PW p => PMConfig p -> FilePath -> IO AESSecretData
+load_ps' PMConfig{..} fp = flip catch hdl $ do
+  (iv,ct) <- B.splitAt (_Octets sizeAesIV) <$> B.readFile fp
   return
     AESSecretData
       { _asd_iv          = IV         $ Binary iv
@@ -693,6 +821,20 @@
   where
     hdl (_::SomeException) = error _pmc_keystore_msg
 
+-- | marge in the second password store into the first, all definitions in
+-- the second passwords store, except the store's creation time, which is
+-- taken from the first store; any sessions are also merged with the
+-- sessions in the second store taking precedence
+merge_ps :: PasswordStore -> PasswordStore -> PasswordStore
+merge_ps ps ps' =
+  PasswordStore
+    { _ps_comment = _ps_comment ps'
+    , _ps_map     =  Map.unionWith f (_ps_map ps) (_ps_map ps')
+    , _ps_setup   = _ps_setup ps
+    }
+  where
+    f pw pw' = L.over pw_sessions (flip Map.union $ _pw_sessions pw) pw'
+
 random_bytes :: Octets -> (Binary->a) -> IO a
 random_bytes sz f = f . Binary . fst . generateCPRNG (_Octets sz) <$> newCPRNG
 
@@ -737,29 +879,66 @@
 -- The Command Line Parser
 --
 
+-- | run a password manager command abstracy syntax command
+passwordManager' :: PW p => PMConfig p -> PMCommand p -> IO ()
+passwordManager' pmc pmcd =
+  case pmcd of
+    PMCD_version                  -> putStrLn version
+    PMCD_setup          nl mb_t   -> setup              pmc nl  mb_t
+    PMCD_login        y    mb_t   -> login              pmc y   mb_t
+    PMCD_import         fp mb_t   -> import_            pmc fp  mb_t
+    PMCD_load            p mb_t   -> load               pmc p   mb_t
+    PMCD_load_plus     pnm mb_t   -> loadPlus           pmc pnm mb_t
+    PMCD_comment            cmt   -> psComment          pmc cmt
+    PMCD_prime        u  p        -> prime              pmc u $ Just p
+    PMCD_prime_all    u           -> prime              pmc u Nothing
+    PMCD_select          mb snm   -> select             pmc mb snm
+    PMCD_delete_password      p   -> deletePassword     pmc p
+    PMCD_delete_password_plus pnm -> deletePasswordPlus pmc pnm
+    PMCD_delete_session    mb snm -> deleteSession      pmc mb snm
+    PMCD_status         q         -> status             pmc q
+    PMCD_prompt                   -> prompt             pmc
+    PMCD_passwords      b         -> passwords          pmc b
+    PMCD_passwords_plus b         -> passwordsPlus      pmc b
+    PMCD_session     b            -> sessions           pmc True  b Nothing
+    PMCD_sessions    b mb         -> sessions           pmc False b mb
+    PMCD_info        s   p        -> infoPassword       pmc s p
+    PMCD_info_plus   s   pnm      -> infoPasswordPlus   pmc s pnm
+    PMCD_dump        s            -> dump               pmc s
+    PMCD_collect                  -> collectShell       pmc
+    PMCD_sample_script            -> putStr $ maybe "" id $ _pmc_sample_script pmc
 
+-- | the abstract syntax for the passowd manager commands
 data PMCommand p
     = PMCD_version
-    | PMCD_setup  Bool   (Maybe PasswordText)
-    | PMCD_login  Bool   (Maybe PasswordText)
-    | PMCD_load        p (Maybe PasswordText)
+    | PMCD_setup  Bool              (Maybe PasswordText)
+    | PMCD_login  Bool              (Maybe PasswordText)
+    | PMCD_import          FilePath (Maybe PasswordText)
+    | PMCD_load        p            (Maybe PasswordText)
+    | PMCD_load_plus   PasswordName (Maybe PasswordText)
     | PMCD_comment       PasswordStoreComment
     | PMCD_prime     Bool p
     | PMCD_prime_all Bool
     | PMCD_select          (Maybe p) SessionName
     | PMCD_delete_password        p
+    | PMCD_delete_password_plus PasswordName
     | PMCD_delete_session  (Maybe p) SessionName
-    | PMCD_status    Bool
-    | PMCD_passwords Bool
-    | PMCD_sessions  Bool Bool (Maybe p)
-    | PMCD_info      Bool         p
-    | PMCD_dump      Bool
+    | PMCD_status         Bool
+    | PMCD_prompt
+    | PMCD_passwords      Bool
+    | PMCD_passwords_plus Bool
+    | PMCD_session        Bool
+    | PMCD_sessions       Bool (Maybe p)
+    | PMCD_info           Bool         p
+    | PMCD_info_plus      Bool         PasswordName
+    | PMCD_dump           Bool
     | PMCD_collect
     | PMCD_sample_script
     deriving (Show)
 
-parse_command :: PW p => PMConfig p -> [String] -> IO (PMCommand p)
-parse_command pmc = run_parse $ command_info pmc
+-- | parse a passwword manager command
+parseCommand :: PW p => PMConfig p -> [String] -> IO (PMCommand p)
+parseCommand pmc = run_parse $ command_info pmc
 
 command_info :: PW p => PMConfig p -> ParserInfo (PMCommand p)
 command_info pmc =
@@ -773,19 +952,23 @@
 command_parser pmc =
     subparser $ f $ g
      $  command "version"             pi_version
-     <> command "setup"               pi_setup
-     <> command "login"               pi_login
-     <> command "load"                pi_load
+     <> command "setup"              (pi_setup            pmc)
+     <> command "login"              (pi_login            pmc)
+     <> command "import"             (pi_import           pmc)
+     <> command "load"               (pi_load             pmc)
      <> command "comment"             pi_comment
      <> command "prime"               pi_prime
      <> command "prime-all"           pi_prime_all
      <> command "select"              pi_select
-     <> command "delete-password"     pi_delete_password
+     <> command "delete-password"    (pi_delete_password  pmc)
      <> command "delete-session"      pi_delete_session
      <> command "status"              pi_status
+     <> command "prompt"              pi_prompt
      <> command "passwords"           pi_passwords
+     <> command "passwords-plus"      pi_passwords_plus
+     <> command "session"             pi_session
      <> command "sessions"            pi_sessions
-     <> command "info"                pi_info
+     <> command "info"               (pi_info             pmc)
      <> command "collect"             pi_collect
   where
     s = command "sample-load-script"  pi_sample_script
@@ -805,22 +988,28 @@
         (helper <*> pure PMCD_version)
         (progDesc "report the version of this package")
 
-pi_setup :: ParserInfo (PMCommand p)
-pi_setup =
+pi_setup :: PW p => PMConfig p -> ParserInfo (PMCommand p)
+pi_setup pmc =
     h_info
-        (helper <*> (PMCD_setup <$> p_no_login_sw <*> optional p_password_text))
+        (helper <*> (PMCD_setup <$> p_no_login_sw <*> optional (p_password_text True pmc)))
         (progDesc "setup the password store")
 
-pi_login :: ParserInfo (PMCommand p)
-pi_login =
+pi_login :: PW p => PMConfig p -> ParserInfo (PMCommand p)
+pi_login pmc =
     h_info
-        (helper <*> (PMCD_login <$> p_loop_sw <*> optional p_password_text))
+        (helper <*> (PMCD_login <$> p_loop_sw <*> optional (p_password_text True pmc)))
         (progDesc "login to the password manager")
 
-pi_load :: PW p => ParserInfo (PMCommand p)
-pi_load =
+pi_import :: PW p => PMConfig p -> ParserInfo (PMCommand p)
+pi_import pmc =
     h_info
-        (helper <*> (PMCD_load <$> p_pw_id <*> optional p_password_text) <* optional p_load_comment)
+        (helper <*> (PMCD_import <$> p_store_fp <*> optional (p_password_text True pmc)))
+        (progDesc "import the contents of another store")
+
+pi_load :: PW p => PMConfig p -> ParserInfo (PMCommand p)
+pi_load pmc =
+    h_info
+        (helper <*> p_load_command pmc)
         (progDesc "load a password into the store")
 
 pi_comment :: PW p => ParserInfo (PMCommand p)
@@ -847,11 +1036,11 @@
         (helper <*> (PMCD_select <$> optional p_pw_id_opt <*> p_session_name))
         (progDesc "select a client session")
 
-pi_delete_password :: PW p => ParserInfo (PMCommand p)
-pi_delete_password =
+pi_delete_password :: PW p => PMConfig p -> ParserInfo (PMCommand p)
+pi_delete_password pmc =
      h_info
-        (helper <*> (PMCD_delete_password <$> p_pw_id))
-        (progDesc "select a client session")
+        (helper <*> p_delete_password pmc)
+        (progDesc "delete a password from the store")
 
 pi_delete_session :: PW p => ParserInfo (PMCommand p)
 pi_delete_session =
@@ -865,22 +1054,41 @@
         (helper <*> (PMCD_status <$> p_quiet_sw))
         (progDesc "report the status of the password manager")
 
+pi_prompt :: ParserInfo (PMCommand p)
+pi_prompt =
+    h_info
+        (helper <*> (pure PMCD_prompt))
+        (progDesc $ "report the condensed status of the password manager"++
+                                  " (suitable for embedding in a shell prompt")
+
 pi_passwords :: ParserInfo (PMCommand p)
 pi_passwords =
     h_info
         (helper <*> (PMCD_passwords <$> p_brief_sw))
         (progDesc "list the passwords")
 
+pi_passwords_plus :: ParserInfo (PMCommand p)
+pi_passwords_plus =
+    h_info
+        (helper <*> (PMCD_passwords_plus <$> p_brief_sw))
+        (progDesc "list the dynamic ('+'') passwords")
+
+pi_session :: PW p => ParserInfo (PMCommand p)
+pi_session =
+    h_info
+        (helper <*> (PMCD_session <$> p_brief_sw))
+        (progDesc "list the sessions")
+
 pi_sessions :: PW p => ParserInfo (PMCommand p)
 pi_sessions =
     h_info
-        (helper <*> (PMCD_sessions <$> p_active_sw <*> p_brief_sw <*> optional p_pw_id))
+        (helper <*> (PMCD_sessions <$> p_brief_sw <*> optional p_pw_id))
         (progDesc "list the sessions")
 
-pi_info :: PW p => ParserInfo (PMCommand p)
-pi_info =
+pi_info :: PW p => PMConfig p -> ParserInfo (PMCommand p)
+pi_info pmc =
     h_info
-        (helper <*> (PMCD_info <$> p_secret_sw <*> p_pw_id))
+        (helper <*> p_info pmc)
         (progDesc "print out the info on a password, including desriptive text")
 
 pi_dump :: PW p => ParserInfo (PMCommand p)
@@ -902,12 +1110,29 @@
         (helper <*> (pure PMCD_sample_script))
         (progDesc "print a sample script to define keystore passwords in the environment (PM edition)")
 
-p_no_login_sw :: Parser Bool
-p_no_login_sw =
+p_load_command, p_delete_password, p_info :: PW p => PMConfig p -> Parser (PMCommand p)
+
+p_load_command pmc =
+  (PMCD_load_plus <$> p_pl_pw pmc <*> optional (p_password_text False pmc) <|>
+   PMCD_load      <$> p_pw_id     <*> optional (p_password_text False pmc)      ) <* optional p_load_comment
+
+p_delete_password pmc =
+  PMCD_delete_password_plus <$> p_pl_pw pmc                     <|>
+  PMCD_delete_password      <$> p_pw_id
+
+p_info pmc = f <$> p_secret_sw <*> ((Left <$> p_pl_pw pmc) <|> (Right <$> p_pw_id))
+  where
+    f s_sw (Left  pnm) = PMCD_info_plus s_sw pnm
+    f s_sw (Right p  ) = PMCD_info      s_sw p
+
+-- switches
+
+p_brief_sw :: Parser Bool
+p_brief_sw =
     switch
-        (short  'n'            <>
-         long    "no-login"    <>
-         help    "do not launch an interactive shell")
+        (short  'b'            <>
+         long    "brief"        <>
+         help    "list the identifiers only")
 
 p_loop_sw :: Parser Bool
 p_loop_sw =
@@ -916,6 +1141,13 @@
          long    "loop"        <>
          help    "on failure prompt for a new password and try again")
 
+p_no_login_sw :: Parser Bool
+p_no_login_sw =
+    switch
+        (short  'n'            <>
+         long    "no-login"    <>
+         help    "do not launch an interactive shell")
+
 p_quiet_sw :: Parser Bool
 p_quiet_sw =
     switch
@@ -923,19 +1155,11 @@
          long    "quiet"        <>
          help    "don't print anything but report with error codes (0=>logged in)")
 
-p_brief_sw :: Parser Bool
-p_brief_sw =
-    switch
-        (short  'b'            <>
-         long    "brief"        <>
-         help    "list the identifiers only")
-
-p_active_sw :: Parser Bool
-p_active_sw =
+p_sessions_sw :: Parser Bool
+p_sessions_sw =
     switch
-        (short  'a'            <>
-         long    "active"      <>
-         help    "list the active sessions only")
+        (long    "sessions"      <>
+         help    "include the sessions")
 
 p_unprime_sw :: Parser Bool
 p_unprime_sw =
@@ -944,24 +1168,7 @@
          long    "unprime"     <>
          help    "clear the prime status")
 
-p_secret_sw :: Parser Bool
-p_secret_sw =
-    switch
-        (short  's'            <>
-         long    "secret"      <>
-         help    "show the secret password")
-
-p_sessions_sw :: Parser Bool
-p_sessions_sw =
-    switch
-        (long    "sessions"      <>
-         help    "include the sessions")
-
-p_pw_id :: PW p => Parser p
-p_pw_id =
-    argument (parsePwName . PasswordName . T.pack)
-        $  metavar "PASSWORD-ID"
-        <> help    "a password ID"
+-- options
 
 p_pw_id_opt :: PW p => Parser p
 p_pw_id_opt =
@@ -972,35 +1179,64 @@
         <> reader  (maybe (fail "password-id not recognised") return . parsePwName . PasswordName . T.pack)
         <> help    "a password ID"
 
-p_password_text :: Parser PasswordText
-p_password_text =
-    argument (Just . PasswordText . T.pack)
-        $  metavar "PASSWORD-TEXT"
-        <> help    "the text of the password"
+-- arguments
 
-p_session_name :: Parser SessionName
-p_session_name =
-    argument (Just . SessionName . T.pack)
-        $  metavar "SESSION"
-        <> help    "a session name"
+p_comment :: Parser String
+p_comment = unwords <$> many p_word
 
+p_hash :: Parser ()
+p_hash = argument (\s->if s=="#" then Just () else Nothing) $ metavar "#"
+
+h_info :: Parser a -> InfoMod a -> ParserInfo a
+h_info pr = O.info (helper <*> pr)
+
 p_load_comment :: Parser ()
 p_load_comment = const () <$> optional (p_hash <* p_comment)
 
+p_password_text :: PW p => Bool -> PMConfig p -> Parser PasswordText
+p_password_text hp pmc =
+    argument (Just . cond_hash hp pmc)
+        $  metavar "PASSWORD-TEXT"
+        <> help    "the text of the password"
+
+p_pw_id :: PW p => Parser p
+p_pw_id =
+    argument (parsePwName . PasswordName . T.pack)
+        $  metavar "PASSWORD-ID"
+        <> help    "a password ID"
+
+p_pl_pw :: PW p => PMConfig p -> Parser PasswordName
+p_pl_pw pmc =
+    argument (parse_plus_pw pmc)
+        $  metavar "+PASSWORD"
+        <> help    "a dynamic (plus) password name"
+
 p_ps_comment :: Parser PasswordStoreComment
 p_ps_comment = PasswordStoreComment . T.pack <$> p_comment
 
-p_hash :: Parser ()
-p_hash = argument (\s->if s=="#" then Just () else Nothing) $ metavar "#"
+p_secret_sw :: Parser Bool
+p_secret_sw =
+    switch
+        (short  's'            <>
+         long    "secret"      <>
+         help    "show the secret password")
 
-p_comment :: Parser String
-p_comment = unwords <$> many p_word
+p_session_name :: Parser SessionName
+p_session_name =
+    argument (Just . SessionName . T.pack)
+        $  metavar "SESSION"
+        <> help    "a session name"
 
+p_store_fp :: Parser FilePath
+p_store_fp =
+    argument Just
+        $  metavar "STORE"
+        <> help    "file containing the password store to import"
+
 p_word :: Parser String
 p_word = argument Just $ metavar "WORD"
 
-h_info :: Parser a -> InfoMod a -> ParserInfo a
-h_info pr = O.info (helper <*> pr)
+-- run_parse
 
 run_parse :: ParserInfo a -> [String] -> IO a
 run_parse pinfo args =
@@ -1018,3 +1254,21 @@
       msg   <- execCompletion compl progn
       putStr msg
       exitWith ExitSuccess
+
+-- plus helpers
+
+parse_plus_pw :: PW p => PMConfig p -> String -> Maybe PasswordName
+parse_plus_pw pmc s_ = case s_ of
+  '+':s | isJust $ _pmc_plus_env_var pmc pnm
+    -> Just pnm
+    where
+      pnm = PasswordName $ T.pack s
+  _ -> Nothing
+
+plussify :: PasswordName -> PasswordName
+plussify = PasswordName . (T.cons '+') . _PasswordName
+
+is_plus :: PasswordName -> Maybe PasswordName
+is_plus pnm = case T.unpack $ _PasswordName pnm of
+  '+':s -> Just $ PasswordName $ T.pack s
+  _     -> Nothing
diff --git a/src/Data/KeyStore/Version.hs b/src/Data/KeyStore/Version.hs
--- a/src/Data/KeyStore/Version.hs
+++ b/src/Data/KeyStore/Version.hs
@@ -6,4 +6,4 @@
     (a,b,c,d) = versionTuple
 
 versionTuple :: (Int,Int,Int,Int)
-versionTuple = (0,5,1,1)
+versionTuple = (0,6,0,0)
