diff --git a/core-program.cabal b/core-program.cabal
--- a/core-program.cabal
+++ b/core-program.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           core-program
-version:        0.6.2.2
+version:        0.6.3.0
 synopsis:       Opinionated Haskell Interoperability
 description:    A library to help build command-line programs, both tools and
                 longer-running daemons.
@@ -22,12 +22,12 @@
 bug-reports:    https://github.com/aesiniath/unbeliever/issues
 author:         Andrew Cowie <istathar@gmail.com>
 maintainer:     Andrew Cowie <istathar@gmail.com>
-copyright:      © 2018-2022 Athae Eredh Siniath and Others
+copyright:      © 2018-2023 Athae Eredh Siniath and Others
 license:        MIT
 license-file:   LICENSE
 build-type:     Simple
 tested-with:
-    GHC == 8.10.7, GHC == 9.2.4
+    GHC == 8.10.7, GHC == 9.2.5
 
 source-repository head
   type: git
diff --git a/lib/Core/Program.hs b/lib/Core/Program.hs
--- a/lib/Core/Program.hs
+++ b/lib/Core/Program.hs
@@ -1,4 +1,4 @@
-{-# OPTIONS_HADDOCK not-home #-}
+{-# OPTIONS_HADDOCK not-home, prune #-}
 
 -- actually, they're there to group implementation too, but hey.
 
@@ -20,8 +20,7 @@
       -- |
       -- A top-level Program type giving you unified access to logging, concurrency,
       -- and more.
-        module Core.Program.Context
-    , module Core.Program.Execute
+      module Core.Program.Execute
     , module Core.Program.Threads
     , module Core.Program.Unlift
     , module Core.Program.Metadata
@@ -49,7 +48,6 @@
 where
 
 import Core.Program.Arguments
-import Core.Program.Context
 import Core.Program.Exceptions
 import Core.Program.Execute
 import Core.Program.Logging
diff --git a/lib/Core/Program/Context.hs b/lib/Core/Program/Context.hs
--- a/lib/Core/Program/Context.hs
+++ b/lib/Core/Program/Context.hs
@@ -310,7 +310,8 @@
 getContext :: Program τ (Context τ)
 getContext = do
     context <- ask
-    return context
+    pure context
+{-# INLINABLE getContext #-}
 
 {- |
 Run a subprogram from within a lifted @IO@ block.
diff --git a/lib/Core/Program/Execute.hs b/lib/Core/Program/Execute.hs
--- a/lib/Core/Program/Execute.hs
+++ b/lib/Core/Program/Execute.hs
@@ -77,6 +77,7 @@
     , getConsoleWidth
     , getApplicationState
     , setApplicationState
+    , changeProgram
 
       -- * Useful actions
     , outputEntire
@@ -117,6 +118,7 @@
     ( MVar
     , modifyMVar_
     , newEmptyMVar
+    , newMVar
     , putMVar
     , readMVar
     , tryPutMVar
@@ -581,6 +583,57 @@
     liftIO $ do
         let v = applicationDataFrom context
         modifyMVar_ v (\_ -> pure user)
+
+{- |
+Sometimes you need to change the type of the application state from what is
+present at the top-level when the program starts.
+
+While the original intent of providing an initial value of type @τ@ to
+'configure' was that your application state would be available at startup, an
+alternative pattern is to form the application state as the first actions that
+your program takes in the 'Program' @τ@ monad. This is especially common if you
+are processing command-line options. In that case, you may find it useful to
+initialize the program at type 'None', say, and then change to the 'Program'
+@υ@ monad you intend to run through the actual program with once the full
+settings object is available. You can do that using this function.
+
+For example:
+
+@
+main :: 'IO' ()
+main = do
+    context <- 'Core.Program.Execute.configure' \"1.0\" 'None' ('simpleConfig' ...)
+    'Core.Program.Execute.executeWith' context program1
+
+program1 :: 'Program' 'None' ()
+program1 = do
+    -- do things to form top-level application state
+    let settings =
+            Settings
+                { ...
+                }
+    
+    'changeProgram' settings program2
+
+program2 :: 'Program' Settings ()
+program2 = do
+    -- now carry on with application logic
+    ...
+@
+
+This allows your code do do 'queryOptionValue' and the like in @program1@ and
+then, once all the settings and initialization is complete, you can switch to
+the actual type you intend to run at in @program2@.
+
+@since 0.6.3
+-}
+changeProgram :: υ -> Program υ α -> Program τ α
+changeProgram user' program = do
+    context1 <- ask
+    liftIO $ do
+        u <- newMVar user'
+        let context2 = context1 {applicationDataFrom = u}
+        subProgram context2 program
 
 {- |
 Write the supplied @Bytes@ to the given @Handle@. Note that in contrast to
