diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,3 @@
+# 0.0.16.0
+
+* Initial version
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2024 Tom Ellis
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/bluefin-random.cabal b/bluefin-random.cabal
new file mode 100644
--- /dev/null
+++ b/bluefin-random.cabal
@@ -0,0 +1,84 @@
+cabal-version:      3.0
+name:               bluefin-random
+version:            0.0.16.0
+license:            MIT
+license-file:       LICENSE
+author:             Tom Ellis
+maintainer:         Tom Ellis
+build-type:         Simple
+extra-doc-files:    CHANGELOG.md
+description:        The Bluefin effect system, random generators
+synopsis:           The Bluefin effect system, random generators
+homepage:           https://github.com/tomjaguarpaw/bluefin
+bug-reports:        https://github.com/tomjaguarpaw/bluefin/issues
+
+common defaults
+    ghc-options: -Wall
+    default-extensions:
+      -- GHC2021
+      BangPatterns
+      BinaryLiterals
+      ConstrainedClassMethods
+      ConstraintKinds
+      DeriveDataTypeable
+      DeriveFoldable
+      DeriveFunctor
+      DeriveGeneric
+      DeriveLift
+      DeriveTraversable
+      DoAndIfThenElse
+      EmptyCase
+      EmptyDataDecls
+      EmptyDataDeriving
+      ExistentialQuantification
+      ExplicitForAll
+      -- Not available until 9.2
+      -- FieldSelectors
+      FlexibleContexts
+      FlexibleInstances
+      ForeignFunctionInterface
+      GADTSyntax
+      GeneralisedNewtypeDeriving
+      HexFloatLiterals
+      ImplicitPrelude
+      -- Not available until 8.10
+      -- ImportQualifiedPost
+      InstanceSigs
+      KindSignatures
+      MonomorphismRestriction
+      MultiParamTypeClasses
+      NamedFieldPuns
+      NamedWildCards
+      NumericUnderscores
+      PatternGuards
+      PolyKinds
+      PostfixOperators
+      RankNTypes
+      RelaxedPolyRec
+      ScopedTypeVariables
+      StandaloneDeriving
+      -- Not available in 8.6
+      -- StandaloneKindSignatures
+      StarIsType
+      TraditionalRecordSyntax
+      TupleSections
+      TypeApplications
+      TypeOperators
+      TypeSynonymInstances
+      NoExplicitNamespaces
+      -- Others
+      DataKinds
+      DerivingStrategies
+      GADTs
+      LambdaCase
+
+library
+    import:           defaults
+    default-language: Haskell2010
+    hs-source-dirs: src
+    build-depends:
+      base >= 4.12 && < 4.22,
+      random >= 1.3 && < 1.4,
+      bluefin >= 0.0.16.0 && < 0.1
+    exposed-modules:
+      Bluefin.Random
diff --git a/src/Bluefin/Random.hs b/src/Bluefin/Random.hs
new file mode 100644
--- /dev/null
+++ b/src/Bluefin/Random.hs
@@ -0,0 +1,196 @@
+{-# LANGUAGE TypeFamilies #-}
+
+module Bluefin.Random
+  ( -- * Handle
+    Random,
+
+    -- * Handlers
+    withInitStdGen,
+
+    -- ** Special purpose handlers
+    -- $specialpurposehandlers
+    evalRandom,
+    runRandom,
+
+    -- * Effectful operations
+    -- $effectfuloperations
+
+    -- * Internal details
+    -- $internaldetails
+    RandomPure,
+  )
+where
+
+import Bluefin.Compound (Handle)
+import Bluefin.Eff (Eff, Effects, (:&), (:>))
+import Bluefin.IO (IOE, effIO)
+import Bluefin.State (State, get, put, runState)
+import qualified System.Random as Rnd
+import qualified System.Random.Stateful as Rnd
+
+-- $specialpurposehandlers
+--
+-- In the vast majority of cases you should use 'withInitStdGen' and
+-- you won't have any need for these special purpose handlers.
+
+-- $effectfuloperations
+--
+-- To run random operations in Bluefin you should use the random
+-- operations in the "System.Random.Stateful" module from the @random@
+-- package. Here are their type signatures when restricted to
+-- Bluefin's @Random@:
+--
+-- @
+-- 'System.Random.Stateful.uniformM' ::
+--   (Uniform a, RandomGen g, e1 :> es) =>
+--   Random g e1 ->
+--   Eff es a
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformRM' ::
+--   (UniformRange a, RandomGen g, e1 :> es) =>
+--   (a, a) ->
+--   Random g e1 ->
+--   Eff es a
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformListM' ::
+--   (Uniform a, RandomGen g, e1 :> es) =>
+--   Int ->
+--   Random g e1 ->
+--   Eff es [a]
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformListRM' ::
+--   (UniformRange a, RandomGen g, e1 :> es) =>
+--   Int ->
+--   (a, a) ->
+--   Random g e1 ->
+--   Eff es [a]
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformShuffleListM' ::
+--   (RandomGen g, e1 :> es) =>
+--   [a] ->
+--   Random g e1 ->
+--   Eff es [a]
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformByteArrayM' ::
+--   (RandomGen g, e1 :> es) =>
+--   Bool ->
+--   Int ->
+--   Random g e1 ->
+--   Eff es ByteArray
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformByteStringM' ::
+--   (RandomGen g, e1 :> es) =>
+--   Int ->
+--   Random g e1 ->
+--   Eff es ByteString
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformShortByteStringM' ::
+--   (RandomGen g, e1 :> es) =>
+--   Int ->
+--   Random g e1 ->
+--   Eff es ShortByteString
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformDouble01M' ::
+--   (RandomGen g, e1 :> es) =>
+--   Random g e1 ->
+--   Eff es Double
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformDoublePositive01M' ::
+--   (RandomGen g, e1 :> es) =>
+--   Random g e1 ->
+--   Eff es Double
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformFloat01M' ::
+--   (RandomGen g, e1 :> es) =>
+--   Random g e1 ->
+--   Eff es Float
+-- @
+--
+-- @
+-- 'System.Random.Stateful.uniformFloatPositive01M' ::
+--   (RandomGen g, e1 :> es) =>
+--   Random g e1 ->
+--   Eff es Float
+-- @
+
+-- $internaldetails
+--
+-- 'RandomPure' is an internal detail that is used to implement a
+-- 'System.Random.Stateful.FrozenGen' instance for 'Random'.  You may
+-- see it in error messages, so we include it here from completeness.
+-- You will most likely never need to use @RandomPure@ directly.
+
+newtype Random g e = Random (State g e)
+  deriving newtype (Handle)
+
+newtype RandomPure g (e :: Effects) = RandomPure g
+  deriving newtype (Rnd.RandomGen)
+
+instance
+  (e :> es, Rnd.RandomGen g) =>
+  Rnd.StatefulGen (Random g e) (Eff es)
+  where
+  uniformWord64 =
+    flip Rnd.modifyGen Rnd.genWord64
+
+  uniformByteArrayM pinned size =
+    flip Rnd.modifyGen (Rnd.uniformByteArray pinned size)
+
+instance
+  (e :> es, Rnd.RandomGen g) =>
+  Rnd.FrozenGen (RandomPure g e) (Eff es)
+  where
+  type MutableGen (RandomPure g e) (Eff es) = Random g e
+
+  modifyGen (Random s) f = do
+    (a, RandomPure g) <- f . RandomPure <$> get s
+    put s g
+    pure a
+
+runRandom ::
+  g ->
+  (forall e. Random g e -> Eff (e :& es) a) ->
+  -- | ͘
+  Eff es (a, g)
+runRandom g f = runState g (f . Random)
+
+evalRandom ::
+  g ->
+  (forall e. Random g e -> Eff (e :& es) a) ->
+  -- | ͘
+  Eff es a
+evalRandom g f = fst <$> runRandom g f
+
+-- | The simplest way to handle a Bluefin 'Random' effect.  This is
+-- the handler you should use unless you know you have a particular
+-- need to use a @Rnd.RandomGen@ other than @Rnd.StdGen@ or you know
+-- you need to create a @Rnd.StdGen@ seed in a non-standard way.
+withInitStdGen ::
+  (e1 :> es) =>
+  IOE e1 ->
+  (forall e. Random Rnd.StdGen e -> Eff (e :& es) a) ->
+  -- | ͘
+  Eff es a
+withInitStdGen io k = do
+  g <- effIO io Rnd.initStdGen
+  evalRandom g k
