diff --git a/lib/Ribosome/Api/Exists.hs b/lib/Ribosome/Api/Exists.hs
new file mode 100644
--- /dev/null
+++ b/lib/Ribosome/Api/Exists.hs
@@ -0,0 +1,91 @@
+module Ribosome.Api.Exists(
+  sleep,
+  retry,
+  waitForFunction,
+  vimDoesExist,
+  function,
+  epochSeconds,
+) where
+
+import Data.Default.Class (Default(def))
+import Data.Either (isRight)
+import Data.Text.Prettyprint.Doc ((<+>), viaShow)
+import Data.Time.Clock.POSIX (getPOSIXTime)
+import Control.Monad.IO.Class (MonadIO, liftIO)
+import Control.Concurrent (threadDelay)
+import Neovim (
+  Neovim,
+  NvimObject,
+  Object(ObjectInt),
+  Doc,
+  AnsiStyle,
+  toObject,
+  fromObject,
+  vim_call_function',
+  )
+
+data Retry =
+  Retry Int Double
+  deriving Show
+
+instance Default Retry where
+  def = Retry 3 0.1
+
+epochSeconds :: MonadIO f => f Int
+epochSeconds = liftIO $ fmap round getPOSIXTime
+
+sleep :: MonadIO f => Double -> f ()
+sleep seconds = liftIO $ threadDelay $ round $ seconds * 10e6
+
+retry :: MonadIO f => f a -> (a -> f (Either c b)) -> Retry -> f (Either c b)
+retry thunk check (Retry timeout interval) = do
+  start <- epochSeconds
+  step start
+  where
+    step start = do
+      result <- thunk
+      checked <- check result
+      recurse start checked
+    recurse _ (Right b) = return (Right b)
+    recurse start (Left e) = do
+      current <- epochSeconds
+      if (current - start) < timeout
+      then do
+        sleep interval
+        step start
+      else return $ Left e
+
+waitFor :: NvimObject b =>
+  Neovim e Object ->
+  (Object -> Neovim e (Either (Doc AnsiStyle) b)) ->
+  Retry ->
+  Neovim e (Either (Doc AnsiStyle) b)
+waitFor thunk check' =
+  retry thunk check
+  where
+    check result =
+      case fromObject result of
+        Right a -> check' a
+        Left e -> return $ Left e
+
+existsResult :: Object -> Either (Doc AnsiStyle) ()
+existsResult (ObjectInt 1) = Right ()
+existsResult a = Left $ viaShow "weird return type " <+> viaShow a
+
+vimExists :: String -> Neovim e Object
+vimExists entity =
+  vim_call_function' "exists" [toObject entity]
+
+vimDoesExist :: String -> Neovim e Bool
+vimDoesExist entity =
+  fmap (isRight . existsResult) (vimExists entity)
+
+function :: String -> Neovim e Bool
+function name =
+  vimDoesExist ("*" ++ name)
+
+waitForFunction :: String -> Retry -> Neovim e (Either (Doc AnsiStyle) ())
+waitForFunction name =
+  waitFor thunk (return . existsResult)
+  where
+    thunk = vimExists ("*" ++ name)
diff --git a/ribosome.cabal b/ribosome.cabal
--- a/ribosome.cabal
+++ b/ribosome.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 3ce2af49c339666be3a190f46d20dc3ff8292ac3ffedf9e8b62bdc4c3f04a67f
+-- hash: 473e4deafa3bb3e51b7612893daa51020a229009cef026ee00b9974d477e32a0
 
 name:           ribosome
-version:        0.1.1.0
+version:        0.1.2.0
 synopsis:       api extensions for nvim-hs
 description:    Please see the README on GitHub at <https://github.com/tek/proteome-hs>
 category:       Neovim
@@ -28,6 +28,7 @@
   exposed-modules:
       Ribosome.Api.Buffer
       Ribosome.Api.Echo
+      Ribosome.Api.Exists
       Ribosome.Api.Function
       Ribosome.Api.Option
       Ribosome.Api.Path
