diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,7 @@
+# Changelog for prospect
+
+## 0.1  -- 2018-07-10
+
+* First version. Released on an unsuspecting world.
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2018
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Author name here nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,82 @@
+# prospect
+
+[![Build Status](https://travis-ci.org/isovector/prospect.svg?branch=master)](https://travis-ci.org/isovector/prospect) | [Hackage][hackage]
+
+[hackage]: https://hackage.haskell.org/package/prospect
+
+
+## Dedication
+
+> It is absolutely necessary, for the peace and safety of mankind, that some of
+> earth's dark, dead corners and unplumbed depths be let alone; lest sleeping
+> abnormalities wake to resurgent life, and blasphemously surviving nightmares
+> squirm and splash out of their black lairs to newer and wider conquests.
+>
+> H.P. Lovecraft
+
+
+## Overview
+
+`prospect` is a library that provides primitives for exploring functions, and by
+extension, monads. As such, it allows for a best-attempt static analysis of free
+monads. Such power, however, does not come for free; using `prospect` is an
+implicit promise with the Eldrich horrors that you'll tread lightly. Feckless
+wanderers into these depths will be rewarded with naught but terror, madness,
+and runtime crashes.
+
+
+## Usage
+
+The library provides a function, `prospect :: Free f a -> (Maybe a, [f ()])`,
+which can probe the depths of a free monad, finding as many `f` constructors as
+it can before the monad branches dynamically.
+
+Be careful when inspecting the `f ()`s, if any of them depend on variables bound
+in the monad, they will leak exceptions when you are least expecting them. It's
+a good idea to run your `f ()`s through `ensure :: Alternative m => a -> m a`
+after you've scrutinized their constructors.
+
+
+## Example
+
+`prospect` can be used to perform a best-effort static analysis of a free monad:
+
+```haskell
+data Pattern a
+  = Cont (Bool -> a)
+  | Action Int a
+  deriving (Functor, Generic1)
+
+
+cont :: MonadFree Pattern m => m Bool
+cont = liftF $ Cont id
+
+
+action :: MonadFree Pattern m => Int -> m ()
+action i = liftF $ Action i ()
+
+
+success :: (Maybe String, [Pattern ()]
+success = prospect $ do
+  a <- cont
+  action 1
+  pure "success"
+-- success = (Just "success", [Cont (const ()), Action 1 ()])
+
+
+failure :: (Maybe String, [Pattern ()]
+failure = prospect $ do
+  a <- cont
+  action 1
+  if a  -- static analysis ends here, as it would require branching on the
+        -- result of a monadic action
+    then action 2
+    else action 3
+  action 4
+  pure "failure"
+-- failure = (Nothing, [Cont (const ()), Action 1 ()])
+```
+
+In these examples, we can continue analyzing a `Free Pattern` monad until
+the result of its `Cont` continuation is forced.
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/prospect.cabal b/prospect.cabal
new file mode 100644
--- /dev/null
+++ b/prospect.cabal
@@ -0,0 +1,64 @@
+-- This file has been generated from package.yaml by hpack version 0.28.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 60eb5636909f1e5d8ffa88c6dd5b649b6bf724ae3d1e7438cc9dd6f99eda53f1
+
+name:           prospect
+version:        0.1.0.0
+synopsis:       Explore continuations with trepidation
+description:    Please see the README on GitHub at <https://github.com/isovector/prospect#readme>
+category:       Control
+homepage:       https://github.com/isovector/prospect#readme
+bug-reports:    https://github.com/isovector/prospect/issues
+author:         Sandy Maguire
+maintainer:     sandy@sandymaguire.me
+copyright:      2018 Sandy Maguire
+license:        BSD3
+license-file:   LICENSE
+tested-with:    GHC == 8.0.2, GHC == 8.2.1
+build-type:     Simple
+cabal-version:  >= 1.10
+extra-source-files:
+    ChangeLog.md
+    README.md
+
+source-repository head
+  type: git
+  location: https://github.com/isovector/prospect
+
+library
+  exposed-modules:
+      Control.Monad.Prospect
+      Lib
+  other-modules:
+      Paths_prospect
+  hs-source-dirs:
+      src
+  ghc-options: -Wall
+  build-depends:
+      base >=4.7 && <5
+    , deepseq
+    , free
+    , kan-extensions
+    , mtl
+    , transformers
+  default-language: Haskell2010
+
+test-suite prospect-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Paths_prospect
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , deepseq
+    , free
+    , hspec
+    , inspection-testing >=0.3
+    , kan-extensions
+    , prospect
+  default-language: Haskell2010
diff --git a/src/Control/Monad/Prospect.hs b/src/Control/Monad/Prospect.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/Prospect.hs
@@ -0,0 +1,186 @@
+{-# LANGUAGE AllowAmbiguousTypes   #-}
+{-# LANGUAGE BangPatterns          #-}
+{-# LANGUAGE DataKinds             #-}
+{-# LANGUAGE DeriveFunctor         #-}
+{-# LANGUAGE DeriveGeneric         #-}
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE KindSignatures        #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE RankNTypes            #-}
+{-# LANGUAGE ScopedTypeVariables   #-}
+{-# LANGUAGE TypeApplications      #-}
+{-# LANGUAGE TypeOperators         #-}
+{-# LANGUAGE UndecidableInstances  #-}
+
+module Control.Monad.Prospect
+  ( -- * Prospecting of free monads
+    prospect
+  , survey
+  , explore
+
+  -- * Guesswork
+  , guess
+  , given
+  , verify
+  , ensure
+  , proceed
+  , Guess (..)
+  ) where
+
+import Control.Applicative (Alternative (..))
+import Control.DeepSeq (NFData, force)
+import Control.Exception (Exception, throw, catch)
+import Control.Monad.Free
+import Control.Monad.Trans.Maybe (runMaybeT)
+import Control.Monad.Writer.Strict (runWriter, tell)
+import GHC.Generics
+import GHC.TypeLits
+import System.IO.Unsafe (unsafePerformIO)
+
+
+
+------------------------------------------------------------------------------
+-- | Perform a best-effort analysis of a free monad.
+survey
+    :: Functor f
+    => (forall b. f (Free f b) -> Free f b)
+       -- ^ The following function. Consider using 'explore' to get an
+       -- automatic implementation for this.
+    -> Free f a
+    -> (Maybe a, [f ()])
+survey c = runWriter . runMaybeT . go
+  where
+    go (Pure a) = verify a
+    go (Free f) = do
+      tell . pure $ () <$ f
+      given go $ c f
+    {-# INLINE go #-}
+
+
+------------------------------------------------------------------------------
+-- | Perform a best-effort analysis of a free monad by automatically
+-- 'explore'ing it.
+prospect
+    :: (Functor f, Generic1 f, GExplore f (Rep1 f))
+    => Free f a
+    -> (Maybe a, [f ()])
+prospect = survey explore
+
+
+------------------------------------------------------------------------------
+-- | The underlying machinery of 'guess'.
+data Guess = Guess
+  deriving (Show, Eq)
+instance Exception Guess
+
+
+------------------------------------------------------------------------------
+-- | A 'guess' is a bottom whose evaluation can be caught by way of 'verify' or
+-- 'given'. It can be used to follow continuations in a free monad until it
+-- branches.
+guess :: a
+guess = throw Guess
+{-# INLINE guess #-}
+
+
+------------------------------------------------------------------------------
+-- | Attempt to evaluate the pure value 'a', returning 'empty' if it was
+-- a 'guess'.
+verify :: Alternative f => a -> f a
+verify = given pure
+{-# INLINE verify #-}
+
+
+------------------------------------------------------------------------------
+-- | Like 'verify', but much stricter.
+ensure :: (Alternative f, NFData a) => a -> f a
+ensure = proceed pure
+{-# INLINE ensure #-}
+
+
+------------------------------------------------------------------------------
+-- | Strictly attempt a function application, returning 'empty' if the argument
+-- was a 'guess'.
+given :: Alternative f => (a -> f b) -> a -> f b
+given f a = unsafePerformIO $ do
+  catch
+    (let !_ = a
+      in pure $ f a)
+    (\(_ :: Guess) -> pure empty)
+{-# INLINE given #-}
+
+
+------------------------------------------------------------------------------
+-- | Like `given`, but much stricter.
+proceed :: (Alternative f, NFData a) => (a -> f b) -> a -> f b
+proceed f a = unsafePerformIO $ do
+  catch
+    (let !_ = force a
+      in pure $ f a)
+    (\(_ :: Guess) -> pure empty)
+{-# INLINE proceed #-}
+
+
+------------------------------------------------------------------------------
+-- | Helper class to derive 'explore' generically.
+class GExplore (p :: * -> *) f where
+  gexplore :: f b -> b
+
+instance TypeError
+    (  'Text "Missing continuation parameter when attempting to derive 'explore'"
+ ':$$: 'Text "Expected a type variable, but got "
+ ':<>: 'ShowType a
+    )
+      => GExplore p (K1 _1 a) where
+  gexplore = undefined
+  {-# INLINE gexplore #-}
+
+instance {-# OVERLAPPING #-} TypeError
+    (  'Text "Missing continuation parameter when attempting to derive 'explore'"
+ ':$$: 'Text "Expected a type variable, but the constructor '"
+ ':<>: 'Text tyConName
+ ':<>: 'Text "' has none"
+    )
+      => GExplore p (C1 ('MetaCons tyConName _b _c) U1) where
+  gexplore = undefined
+  {-# INLINE gexplore #-}
+
+instance GExplore p V1 where
+  gexplore _ = undefined
+  {-# INLINE gexplore #-}
+
+instance Functor p => GExplore p (Rec1 ((->) a)) where
+  gexplore (Rec1 z) = z guess
+  {-# INLINE gexplore #-}
+
+instance GExplore p Par1 where
+  gexplore (Par1 z) = z
+  {-# INLINE gexplore #-}
+
+instance GExplore p g => GExplore p (f :*: g) where
+  gexplore (_ :*: b) = gexplore @p b
+  {-# INLINE gexplore #-}
+
+instance (GExplore p f, GExplore p g) => GExplore p (f :+: g) where
+  gexplore (L1 f) = gexplore @p f
+  gexplore (R1 g) = gexplore @p g
+  {-# INLINE gexplore #-}
+
+instance GExplore p f => GExplore p (M1 _1 _2 f) where
+  gexplore (M1 f) = gexplore @p f
+  {-# INLINE gexplore #-}
+
+
+------------------------------------------------------------------------------
+-- | An automatically generated (and unsafe) f-algebra capable of tearing down
+-- any functor 'f' with a 'Generic1' instance. 'explore' will 'guess' its way
+-- through any continuations it discovers.
+explore
+    :: forall f a
+     . (Generic1 f, GExplore f (Rep1 f))
+    => f a
+    -> a
+explore = gexplore @f . from1
+{-# INLINE explore #-}
+
diff --git a/src/Lib.hs b/src/Lib.hs
new file mode 100644
--- /dev/null
+++ b/src/Lib.hs
@@ -0,0 +1,6 @@
+module Lib
+    ( someFunc
+    ) where
+
+someFunc :: IO ()
+someFunc = putStrLn "someFunc"
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,180 @@
+{-# LANGUAGE BangPatterns     #-}
+{-# LANGUAGE DeriveFunctor    #-}
+{-# LANGUAGE DeriveGeneric    #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RankNTypes       #-}
+{-# LANGUAGE TemplateHaskell  #-}
+{-# LANGUAGE TypeApplications #-}
+
+{-# OPTIONS_GHC -O -fplugin Test.Inspection.Plugin #-}
+
+module Main where
+
+import Control.DeepSeq (NFData (..), force)
+import Control.Exception (evaluate)
+import Control.Monad.Codensity (improve)
+import Control.Monad.Free (MonadFree, Free (..), liftF)
+import Control.Monad.Prospect
+import GHC.Generics (Generic1)
+import Test.Hspec
+import Test.Inspection (Result (..), inspectTest, hasNoGenerics)
+
+
+
+main :: IO ()
+main = hspec $ do
+  let contT = Cont  $ const ()
+      contI = ContI $ const ()
+
+  describe "prospect" $ do
+    testFree "should lazily produce values"
+                 (Just "hello")
+                 [ contT
+                 , contT
+                 ] $ do
+      _ <- cont
+      _ <- cont
+      pure "hello"
+
+    testFree "should not be cursed for producer patterns"
+                 (Just ())
+                 [ Action 1 ()
+                 , Action 2 ()
+                 ] $ do
+      action 1
+      action 2
+
+    testFree "should not crash for a single continuation"
+                 Nothing
+                 [ contT
+                 ] $ do
+      cont
+
+    testFree "should stop on an explicit bang pattern"
+                 Nothing
+                 [ contT
+                 ] $ do
+      !x <- cont
+      pure "error"
+
+    it "should not crash for guess" $ do
+      prospect (pure @(Free Pattern) $ guess @Int)
+        `shouldBe` (Nothing, [])
+
+    it "should not crash for guess >>= pure" $ do
+      prospect (pure @(Free Pattern) (guess @Int) >>= pure)
+        `shouldBe` (Nothing, [])
+
+    it "nothing you hold dear is safe" $ do
+      let (u, z) = prospect $ do
+            action $ guess @Int
+      evaluate (force (u, z)) `shouldThrow` (== Guess)
+
+    testFree "should stop before branching"
+                 Nothing
+                 [ contT
+                 , Action 5 ()
+                 , contT
+                 ] $ do
+      x <- cont
+      action 5
+      y <- cont
+      if x
+         then pure True
+         else cont
+
+  describe "verify" $ do
+    it "should catch guesses" $ do
+      verify guess `shouldBe` Nothing @()
+      verify (guess + guess) `shouldBe` Nothing @Int
+      verify (guess @[()]) `shouldBe` []
+
+    it "should not mess with values" $ do
+      verify 0 `shouldBe` Just @Int 0
+      verify (1 + 2) `shouldBe` Just @Int 3
+
+    it "should respect strictness otherwise" $ do
+      verify (const 3 guess) `shouldBe` Just @Int 3
+
+
+  describe "ensure" $ do
+    let (a, ms) = prospect $ action 1 >> conti >>= action
+
+    it "should crash if you're foolish" $ do
+      a `shouldBe` Just ()
+      evaluate (force $ show ms) `shouldThrow` (== Guess)
+
+    it "shouldn't crash if you're wise" $ do
+      a `shouldBe` Just ()
+      fmap ensure ms
+        `shouldBe` [Just (Action 1 ()), Just contI, Nothing]
+
+
+  describe "explore" $ do
+    it "should optimize away its generics" $ do
+      $(inspectTest $ hasNoGenerics 'explorePattern)
+        `shouldSatisfy` isSuccess
+
+
+data Pattern a
+  = Cont (Bool -> a)
+  | ContI (Int -> a)
+  | Action Int a
+  deriving (Functor, Generic1)
+
+instance Eq a => Eq (Pattern a) where
+  Cont f == Cont g
+      = f True  == g True
+     && f False == g False
+  ContI _ == ContI _ = True
+  Action i a == Action j b
+      = i == j
+     && a == b
+  _ == _ = False
+
+instance Show (Pattern a) where
+  show (Cont _)      = "Cont"
+  show (ContI _)     = "ContI"
+  show (Action i _ ) = "Action " ++ show i
+
+
+instance NFData a => NFData (Pattern a) where
+  rnf (Cont f)     = seq f ()
+  rnf (ContI f)    = seq f ()
+  rnf (Action i a) = seq i ()
+
+
+cont :: MonadFree Pattern m => m Bool
+cont = liftF $ Cont id
+
+
+conti :: MonadFree Pattern m => m Int
+conti = liftF $ ContI id
+
+
+action :: MonadFree Pattern m => Int -> m ()
+action i = liftF $ Action i ()
+
+
+explorePattern :: Pattern (Free Pattern a) -> Free Pattern a
+explorePattern = explore
+
+
+isSuccess :: Result -> Bool
+isSuccess (Success _) = True
+isSuccess (Failure _) = False
+
+
+testFree
+    :: (Eq a, Show a)
+    => String
+    -> Maybe a
+    -> [Pattern ()]
+    -> (forall m. (MonadFree Pattern m) => m a)
+    -> SpecWith (Arg Expectation)
+testFree z v cs m =
+  let (a, ms) = prospect $ improve m
+   in it z $ do
+        a  `shouldBe` v
+        ms `shouldBe` cs
+
