diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,18 @@
 Brick changelog
 ---------------
 
+0.23
+----
+
+API changes:
+ * getVtyHandle: always return a Vty handle rather than Maybe
+   (Previously, in appStartEvent you'd get Nothing because Vty had
+   not been initialized yet. This made various use cases impossible
+   to satisfy because appStartEvent is a natural place to get initial
+   terminal state from Vty. This change makes it so that a Vty handle is
+   always available, even in appStartEvent.)
+ * txtWrapWith: added missing haddock
+
 0.22
 ----
 
diff --git a/brick.cabal b/brick.cabal
--- a/brick.cabal
+++ b/brick.cabal
@@ -1,5 +1,5 @@
 name:                brick
-version:             0.22
+version:             0.23
 synopsis:            A declarative terminal user interface library
 description:
   Write terminal applications painlessly with 'brick'! You write an
diff --git a/docs/guide.rst b/docs/guide.rst
--- a/docs/guide.rst
+++ b/docs/guide.rst
@@ -832,11 +832,9 @@
 
    do
      vty <- Brick.Main.getVtyHandle
-     case vty of
-       Nothing -> return ()
-       Just v -> let output = outputIface v
-                 in when (supportsMode output BracketedPaste) $
-                      liftIO $ setMode output BracketedPaste True
+     let output = outputIface vty
+     when (supportsMode output BracketedPaste) $
+         liftIO $ setMode output BracketedPaste True
 
 Once enabled, paste mode will generate Vty ``EvPaste`` events. These
 events will give you the entire pasted content as a ``ByteString`` which
@@ -855,11 +853,9 @@
 
    do
      vty <- Brick.Main.getVtyHandle
-     case vty of
-       Nothing -> return ()
-       Just v -> let output = outputIface vt
-                 in when (supportsMode output Mouse) $
-                      liftIO $ setMode output Mouse True
+     let output = outputIface vty
+     when (supportsMode output Mouse) $
+       liftIO $ setMode output Mouse True
 
 Bear in mind that some terminals do not support mouse interaction, so
 use Vty's ``getModeStatus`` to find out whether your terminal will
diff --git a/src/Brick/Main.hs b/src/Brick/Main.hs
--- a/src/Brick/Main.hs
+++ b/src/Brick/Main.hs
@@ -154,7 +154,7 @@
 readBrickEvent brickChan userChan = either id AppEvent <$> readBChan2 brickChan userChan
 
 runWithNewVty :: (Ord n)
-              => IO Vty
+              => Vty
               -> BChan (BrickEvent n e)
               -> Maybe (BChan e)
               -> App s e n
@@ -198,20 +198,22 @@
            -- ^ The initial application state.
            -> IO s
 customMain buildVty mUserChan app initialAppState = do
-    let run rs st brickChan = do
-            result <- runWithNewVty buildVty brickChan mUserChan app rs st
+    initialVty <- buildVty
+    let run vty rs st brickChan = do
+            result <- runWithNewVty vty brickChan mUserChan app rs st
             case result of
                 InternalHalt s -> return s
                 InternalSuspendAndResume newRS action -> do
                     newAppState <- action
-                    run newRS newAppState brickChan
+                    newVty <- buildVty
+                    run newVty newRS newAppState brickChan
 
         emptyES = ES [] []
-        eventRO = EventRO M.empty Nothing mempty
+        eventRO = EventRO M.empty initialVty mempty
     (st, eState) <- runStateT (runReaderT (runEventM (appStartEvent app initialAppState)) eventRO) emptyES
     let initialRS = RS M.empty (esScrollRequests eState) S.empty mempty []
     brickChan <- newBChan 20
-    run initialRS st brickChan
+    run initialVty initialRS st brickChan
 
 supplyVtyEvents :: Vty -> BChan (BrickEvent n e) -> IO ()
 supplyVtyEvents vty chan =
@@ -271,7 +273,7 @@
         _ -> return (e, firstRS, exts)
 
     let emptyES = ES [] []
-        eventRO = EventRO (viewportMap nextRS) (Just vty) nextExts
+        eventRO = EventRO (viewportMap nextRS) vty nextExts
 
     (next, eState) <- runStateT (runReaderT (runEventM (appHandleEvent app appState e'))
                                 eventRO) emptyES
@@ -320,7 +322,7 @@
 findClickedExtents_ pos = reverse . filter (clickedExtent pos)
 
 -- | Get the Vty handle currently in use.
-getVtyHandle :: EventM n (Maybe Vty)
+getVtyHandle :: EventM n Vty
 getVtyHandle = EventM $ asks eventVtyHandle
 
 -- | Invalidate the rendering cache entry with the specified resource
@@ -334,9 +336,8 @@
 invalidateCache = EventM $ do
     lift $ modify (\s -> s { cacheInvalidateRequests = InvalidateEntire : cacheInvalidateRequests s })
 
-withVty :: IO Vty -> (Vty -> IO a) -> IO a
-withVty buildVty useVty = do
-    vty <- buildVty
+withVty :: Vty -> (Vty -> IO a) -> IO a
+withVty vty useVty = do
     useVty vty `finally` shutdown vty
 
 renderApp :: Vty -> App s e n -> s -> RenderState n -> IO (RenderState n, [Extent n])
diff --git a/src/Brick/Types/Internal.hs b/src/Brick/Types/Internal.hs
--- a/src/Brick/Types/Internal.hs
+++ b/src/Brick/Types/Internal.hs
@@ -112,7 +112,7 @@
               deriving (Show)
 
 data EventRO n = EventRO { eventViewportMap :: M.Map n Viewport
-                         , eventVtyHandle :: Maybe Vty
+                         , eventVtyHandle :: Vty
                          , latestExtents :: [Extent n]
                          }
 
diff --git a/src/Brick/Widgets/Core.hs b/src/Brick/Widgets/Core.hs
--- a/src/Brick/Widgets/Core.hs
+++ b/src/Brick/Widgets/Core.hs
@@ -220,6 +220,8 @@
 txtWrap :: T.Text -> Widget n
 txtWrap = txtWrapWith defaultWrapSettings
 
+-- | Make a widget from text, but wrap the words in the input's lines at
+-- the available width using the specified wrapping settings.
 txtWrapWith :: WrapSettings -> T.Text -> Widget n
 txtWrapWith settings s =
     Widget Fixed Fixed $ do
