diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,9 @@
+# Revision history for benri-hspec
+
+`benri-hspec` uses [PVP Versioning][1].
+
+## 0.1.0.0 -- 2022-11-10
+
+* Initial version.
+
+[1]: https://pvp.haskell.org
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2022, Tim Emiola
+
+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 Tim Emiola 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.lhs b/README.lhs
new file mode 100644
--- /dev/null
+++ b/README.lhs
@@ -0,0 +1,100 @@
+# benri-hspec
+
+[![GitHub CI](https://github.com/adetokunbo/benri-hspec/actions/workflows/ci.yml/badge.svg)](https://github.com/adetokunbo/benri-hspec/actions)
+[![Stackage Nightly](http://stackage.org/package/benri-hspec/badge/nightly)](http://stackage.org/nightly/package/benri-hspec)
+[![Hackage][hackage-badge]][hackage]
+[![Hackage Dependencies][hackage-deps-badge]][hackage-deps]
+[![BSD3](https://img.shields.io/badge/license-BSD3-green.svg?dummy)](https://github.com/adetokunbo/benri-hspec/blob/master/LICENSE)
+
+`benri-hspec` is a small library of __convenient__ functions for writing hspec tests.
+
+It's simplifies test code that returns `Either` or `Maybe` types from monadic code.
+
+## Example
+
+```haskell
+{-# LANGUAGE OverloadedStrings #-}
+
+import System.Environment
+  ( lookupEnv,
+    setEnv,
+    unsetEnv
+   )
+import Text.Read   (readEither)
+import Test.Hspec
+import Test.Hspec.Benri
+
+spec :: Spec
+spec = describe "Checking the functions in Test.Hspec.Benri" $ before_ clearIt $ do
+  context "endsJust_" $ do
+    it "should succeed if a Just is returned" $ do
+      setIt
+      endsJust_ getIt
+
+  context "endsJust" $ do
+    it "should match the Just value" $ do
+      setIt
+      getIt `endsJust` "1"
+
+  context "endsNothing" $ do
+    it "should succeed when the action returns Nothing" $ do
+      setIt
+      getIt `endsJust` "1"
+      clearIt
+      endsNothing getIt
+
+  context "endsLeft_" $ do
+    it "should succeed if a Left is returned" $ do
+      setNotInt
+      endsLeft_ getAsInt
+
+  context "endsLeft" $ do
+    it "should match the Left value" $ getAsInt `endsLeft` "not set!"
+
+  context "endsRight_" $ do
+    it "should succeed if a Right is returned" $ do
+      setIt
+      endsRight_ getAsInt
+
+  context "endsRight" $ do
+    it "should match the Right value" $ do
+      setIt
+      getAsInt `endsRight` 1
+
+  context "endsThen" $ do
+    it "should implement the behaviour of the other functions easily" $ do
+      setIt
+      getIt `endsThen` (== (Just "1"))
+      clearIt
+      getIt `endsThen` (== Nothing)
+      getAsInt `endsThen` (== (Left "not set!"))
+      setIt
+      getAsInt `endsThen` (== (Right 1))
+
+getIt :: IO (Maybe String)
+getIt = lookupEnv envName
+
+getAsInt :: IO (Either String Int)
+getAsInt = maybe (Left "not set!") readEither <$> getIt
+
+setIt :: IO ()
+setIt = setEnv envName "1"
+
+setNotInt :: IO ()
+setNotInt = setEnv envName "foo"
+
+clearIt :: IO ()
+clearIt = unsetEnv envName
+
+envName :: String
+envName = "AN_ENV_VAR"
+
+main :: IO ()
+main = hspec spec
+
+```
+
+[hackage-deps-badge]: <https://img.shields.io/hackage-deps/v/benri-hspec.svg>
+[hackage-deps]:       <http://packdeps.haskellers.com/feed?needle=benri-hspec>
+[hackage-badge]:      <https://img.shields.io/hackage/v/benri-hspec.svg>
+[hackage]:            <https://hackage.haskell.org/package/benri-hspec>
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/benri-hspec.cabal b/benri-hspec.cabal
new file mode 100644
--- /dev/null
+++ b/benri-hspec.cabal
@@ -0,0 +1,59 @@
+cabal-version:      3.0
+name:               benri-hspec
+version:            0.1.0.0
+synopsis:           Simplify tests where Either or Maybe types are returned from monadic code
+description:
+  A small library of __convenient__ functions for writing hspec tests.
+
+  It's simplifies test code that returns `Either` or `Maybe` types from monadic code.
+
+  The [README](https://github.com/adetokunbo/benri-hspec#readme) provides usage examples.
+
+license:            BSD-3-Clause
+license-file:       LICENSE
+author:             Tim Emiola
+maintainer:         adetokunbo@emio.la
+category:           Web
+homepage:           https://github.com/adetokunbo/benri-hspec#readme
+bug-reports:
+  https://github.com/adetokunbo/benri-hspec/issues
+
+build-type:         Simple
+extra-source-files:
+  ChangeLog.md
+
+source-repository head
+  type:     git
+  location: https://github.com/adetokunbo/benri-hspec.git
+
+library
+  exposed-modules:  Test.Hspec.Benri
+  hs-source-dirs:   src
+  build-depends:
+    , base               >=4.10 && <5
+    , hspec              >=2.7.0 && <2.12.0
+
+  default-language: Haskell2010
+  ghc-options:      -Wall -Wincomplete-uni-patterns -Wpartial-fields -fwarn-tabs
+
+
+Flag build-the-readme
+  description: Allow the readme to build
+  default:     False
+
+
+test-suite readme
+  if os(windows) || !flag(build-the-readme)
+    buildable: False
+  else
+    buildable: True
+
+  build-tool-depends: markdown-unlit:markdown-unlit
+  type:             exitcode-stdio-1.0
+  ghc-options:        -pgmL markdown-unlit -threaded -rtsopts -with-rtsopts=-N -Wall -Wincomplete-patterns -Wpartial-fields
+  main-is:            README.lhs
+  default-language:   Haskell2010
+  build-depends:
+    , base
+    , benri-hspec
+    , hspec
diff --git a/src/Test/Hspec/Benri.hs b/src/Test/Hspec/Benri.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/Hspec/Benri.hs
@@ -0,0 +1,95 @@
+{- |
+Module      : Test.Hspec.Benri
+Copyright   : (c) 2022 Tim Emiola
+Maintainer  : Tim Emiola <adetokunbo@emio.la>
+SPDX-License-Identifier: BSD3
+
+Provides \convenient\ functions for writing hspec tests
+-}
+module Test.Hspec.Benri (
+  -- * expect a monadic value
+  endsThen,
+
+  -- * expect a monadic @Maybe@
+  endsJust,
+  endsJust_,
+  endsNothing,
+
+  -- * expect a monadic @Either@
+  endsLeft,
+  endsLeft_,
+  endsRight,
+  endsRight_,
+) where
+
+import Data.Maybe (isJust)
+import Test.Hspec (Expectation, HasCallStack, shouldBe, shouldSatisfy)
+
+
+{- |
+ @action \`endsRight\` @expected@ sets the expectation that @action@
+ returns @Right@ @expected@.
+-}
+endsRight :: (HasCallStack, Show a, Eq a, Show b, Eq b) => IO (Either a b) -> b -> Expectation
+action `endsRight` expected = action >>= (`shouldBe` Right expected)
+
+
+{- |
+ @action \`endsLeft\` @expected@ sets the expectation that @action@
+ returns @Left@ @expected@.
+-}
+endsLeft ::
+  (HasCallStack, Show a, Eq a, Show b, Eq b) => IO (Either a b) -> a -> Expectation
+action `endsLeft` expected = action >>= (`shouldBe` Left expected)
+
+
+{- |
+ @action \`endsRight_\` sets the expectation that @action@
+ returns @Right _@.
+-}
+endsRight_ :: (Show a, Show b) => IO (Either a b) -> IO ()
+endsRight_ action = endsThen action $ either (const False) (const True)
+
+
+{- |
+ @action \`endsLeft_\` sets the expectation that @action@
+ returns @Left _@.
+-}
+endsLeft_ :: (Show a, Show b) => IO (Either a b) -> IO ()
+endsLeft_ action = endsThen action $ either (const True) (const False)
+
+
+{- |
+ @action \`endsJust\`  @expected@ sets the expectation that @action@
+ returns @Just@ @expected@.
+-}
+endsJust ::
+  (HasCallStack, Show a, Eq a) => IO (Maybe a) -> a -> Expectation
+action `endsJust` expected = action >>= (`shouldBe` Just expected)
+
+
+{- |
+ @action \`endsNothing\` expected@ sets the expectation that @action@
+ returns @Nothing@.
+-}
+endsNothing :: (Show a, Eq a) => IO (Maybe a) -> IO ()
+endsNothing action = action >>= (`shouldBe` Nothing)
+
+
+{- |
+ @action \`endsJust_\` sets the expectation that @action@
+ returns @Just _@.
+-}
+endsJust_ :: (Show a) => IO (Maybe a) -> IO ()
+endsJust_ action = endsThen action isJust
+
+
+{- |
+ @action \`endsThen\` expected@ sets the expectation that @action@
+ returns @expected@.
+-}
+endsThen :: (Show a) => IO a -> (a -> Bool) -> IO ()
+endsThen action p = action >>= (`shouldSatisfy` p)
+
+
+infix 1 `endsLeft`, `endsRight`, `endsThen`, `endsJust`
