diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Revision history for oath
+
+## 0.1.0.0 -- YYYY-mm-dd
+
+* First version. Released on an unsuspecting world.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,87 @@
+Oath: composable concurrent computation done right
+----
+
+Oath is an Applicative structures that makes concurrent actions composable.
+
+```haskell
+newtype Oath a = Oath { runOath :: forall r. (STM a -> IO r) -> IO r }
+```
+
+`Oath` is a continuation-passing IO action which takes a transaction to obtain the final result (`STM a`).
+The continuation-passing style makes it easier to release resources in time.
+The easiest way to construct `Oath` is `oath`. It run the supplied action in a separate thread as long as the continuation is running.
+
+```haskell
+oath :: IO a -> Oath a
+oath act = Oath $ \cont -> do
+  v <- newEmptyTMVarIO
+  tid <- forkFinally act (atomically . putTMVar v)
+  let await = takeTMVar v >>= either throwSTM pure
+  cont await `finally` killThread tid
+
+evalOath :: Oath a -> IO a
+evalOath m = runOath m atomically
+```
+
+`Oath` is an `Applicative`, so you can combine multiple `Oath`s. It starts computations without waiting for the results. Run `evalOath` to get the final result. The following code run concurrently `foo :: IO a` and `bar :: IO b`, then applies `f` to these results.
+
+```haskell
+main = evalOath $ f <$> oath foo <*> oath bar
+```
+
+It _does not_ provide a Monad instance because it is logically impossible to define one consistent with the Applicative instance.
+
+Usage
+----
+
+`Oath` abstracts a triple of sending a request, waiting for response, and cancelling a request. If you want to send requests in a deterministic order, you can construct `Oath` directly instead of calling `oath`.
+
+```haskell
+Oath $ \cont -> bracket sendRequest cancelRequest (cont . waitForResponse)
+```
+
+Timeout behaviour can be easily added using the `Alternative` instance and `delay :: Int -> Oath ()`. Or more in general, `<|>` runs both computations until one of them finishes.
+
+```haskell
+-- | An 'Oath' that finishes once the given number of microseconds elapses
+delay :: Int -> Oath ()
+
+oath action <|> delay 100000
+```
+
+Comparison to other packages
+----
+
+[future](https://hackage.haskell.org/package/future-2.0.0/docs/Control-Concurrent-Future.html), [caf](https://hackage.haskell.org/package/caf-0.0.3/docs/Control-Concurrent-Futures.html) and [async](https://hackage.haskell.org/package/async-2.2.4/docs/Control-Concurrent-Async.html) seem solve the same problem. They define abstractions to asynchronous computations. `async` has an applicative `Concurrently` wrapper.
+
+[spawn](https://hackage.haskell.org/package/spawn-0.3/docs/Control-Concurrent-Spawn.html) does not define any datatype. Instead it provides an utility function for `IO` (`spawn :: IO a -> IO (IO a)`). It does not offer a way to cancel a computation.
+
+[promises](https://hackage.haskell.org/package/promises-0.3/docs/Data-Promise.html) provides a monadic interface for pure demand-driven computation. It has nothing to do with concurrency.
+
+[unsafe-promises](https://hackage.haskell.org/package/unsafe-promises-0.0.1.3/docs/Control-Concurrent-Promise-Unsafe.html) creates an IO action that waits for the result on-demand using `unsafeInterleaveIO`.
+
+[futures](https://hackage.haskell.org/package/futures-0.1/docs/Futures.html) provides a wrapper of `forkIO`. There is no way to terminate an action and it does not propagate exceptions.
+
+[promise](https://hackage.haskell.org/package/promise-0.1.0.0/docs/Control-Concurrent-Promise.html) has illegal Applicative and Monad instances; `(<*>)` is not associative and has a bind that's not consistent with `(<*>).`
+
+Performance
+----
+
+```haskell
+bench "oath 10" $ nfIO $ O.evalOath $ traverse (O.oath . pure) [0 :: Int ..9]
+bench "async 10" $ nfIO $ A.runConcurrently $ traverse (A.Concurrently . pure) [0 :: Int ..9]
+```
+
+`Oath`'s overhead of `(<*>)` is less than `Concurrently`. Unlike `Concurrently`, `<*>` itself does not fork threads.
+
+```
+All
+  oath 10:   OK (1.63s)
+    5.78 μs ± 265 ns
+  async 10:  OK (0.21s)
+    12.3 μs ± 767 ns
+  oath 100:  OK (0.22s)
+    52.6 μs ± 4.4 μs
+  async 100: OK (0.23s)
+    109  μs ± 8.4 μs
+```
diff --git a/benchmarks/bench.hs b/benchmarks/bench.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/bench.hs
@@ -0,0 +1,15 @@
+{-# LANGUAGE RankNTypes #-}
+import qualified Oath as O
+import qualified Control.Concurrent.Async as A
+import Test.Tasty.Bench
+import qualified Streamly.Prelude as S
+
+main :: IO ()
+main = defaultMain
+  [ bench "oath 10" $ nfIO $ O.evalOath $ traverse (O.oath . pure) [0 :: Int ..9]
+  , bench "async 10" $ nfIO $ A.runConcurrently $ traverse (A.Concurrently . pure) [0 :: Int ..9]
+  , bench "streamly 10" $ nfIO $ S.drain $ S.fromZipAsync $ traverse (S.fromEffect . pure) [0 :: Int ..9]
+  , bench "oath 100" $ nfIO $ O.evalOath $ traverse (O.oath . pure) [0 :: Int ..99]
+  , bench "async 100" $ nfIO $ A.runConcurrently $ traverse (A.Concurrently . pure) [0 :: Int ..99]
+  , bench "streamly 100" $ nfIO $ S.toList $ S.fromZipAsync $ traverse (S.fromEffect . pure) [0 :: Int ..99]
+  ]
diff --git a/oath.cabal b/oath.cabal
new file mode 100644
--- /dev/null
+++ b/oath.cabal
@@ -0,0 +1,60 @@
+cabal-version:      2.4
+name:               oath
+version:            0.0
+
+-- A short (one-line) description of the package.
+synopsis:           Composable concurrent computation done right
+
+-- A longer description of the package.
+description:        See README.md for details
+
+-- A URL where users can report bugs.
+bug-reports:        https://github.com/fumieval/oath
+
+-- The license under which the package is released.
+license:            BSD-3-Clause
+author:             Fumiaki Kinoshita
+maintainer:         fumiexcel@gmail.com
+
+-- A copyright notice.
+copyright:          Copyright (c) 2021 Fumiaki Kinoshita
+category:           Concurrency
+extra-source-files: CHANGELOG.md, README.md
+
+source-repository head
+  type: git
+  location: https://github.com/fumieval/oath.git
+
+library
+    exposed-modules: Oath
+    -- Modules included in this executable, other than Main.
+    -- other-modules:
+
+    -- LANGUAGE extensions used by modules in this package.
+    -- other-extensions:
+    build-depends:    base >=4.14.1.0 && <4.17, stm, stm-delay
+    hs-source-dirs:   src
+    default-language: Haskell2010
+    ghc-options: -Wall -Wcompat
+
+test-suite test
+    build-depends: base >=4.14.1.0
+        , futures
+        , unsafe-promises
+        , promise
+        , oath
+        , async
+        , streamly
+    type: exitcode-stdio-1.0
+    hs-source-dirs: tests
+    default-language: Haskell2010
+    main-is: test.hs
+    ghc-options: -Wall -Wcompat
+
+benchmark bench
+    type:                exitcode-stdio-1.0
+    main-is:             bench.hs
+    hs-source-dirs:      benchmarks
+    build-depends:       base, tasty-bench, oath, async, streamly
+    ghc-options:         -Wall -threaded -O2
+    default-language:    Haskell2010
diff --git a/src/Oath.hs b/src/Oath.hs
new file mode 100644
--- /dev/null
+++ b/src/Oath.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DerivingVia #-}
+module Oath
+  ( Oath(..)
+  , hoistOath
+  , evalOath
+  , oath
+  , delay
+  , timeout) where
+
+import Control.Applicative
+import Control.Concurrent
+import Control.Concurrent.STM
+import Control.Concurrent.STM.Delay
+import Control.Exception
+import Data.Monoid
+
+-- 'Oath' is an 'Applicative' structure that collects results of one or more computations.
+newtype Oath a = Oath { runOath :: forall r. (STM a -> IO r) -> IO r }
+  deriving Functor
+  deriving (Semigroup, Monoid) via Ap Oath a
+
+hoistOath :: (forall x. STM x -> STM x) -> Oath a -> Oath a
+hoistOath t (Oath m) = Oath $ \cont -> m $ cont . t
+
+evalOath :: Oath a -> IO a
+evalOath m = runOath m atomically
+
+instance Applicative Oath where
+  pure a = Oath $ \cont -> cont (pure a)
+  Oath m <*> Oath n = Oath $ \cont -> m $ \f -> n $ \x -> cont (f <*> x)
+
+instance Alternative Oath where
+  empty = Oath $ \cont -> cont empty
+  Oath m <|> Oath n = Oath $ \cont -> m $ \a -> n $ \b -> cont (a <|> b)
+
+-- | Lift an IO action into an 'Oath', forking a thread.
+-- When the continuation terminates, it kills the thread.
+-- Exception thrown in the thread will be propagated to the result.
+oath :: IO a -> Oath a
+oath act = Oath $ \cont -> do
+  v <- newEmptyTMVarIO
+  tid <- forkFinally act (atomically . putTMVar v)
+  let await = readTMVar v >>= either throwSTM pure
+  cont await `finally` killThread tid
+
+-- | An 'Oath' that finishes once the given number of microseconds elapses
+delay :: Int -> Oath ()
+delay dur = Oath $ \cont -> bracket (newDelay dur) cancelDelay (cont . waitDelay)
+
+-- | Wrap an 'Oath'
+timeout :: Int -> Oath a -> Oath (Maybe a)
+timeout dur m = Just <$> m <|> Nothing <$ delay dur
diff --git a/tests/test.hs b/tests/test.hs
new file mode 100644
--- /dev/null
+++ b/tests/test.hs
@@ -0,0 +1,58 @@
+import qualified Oath
+import qualified Futures
+import qualified Control.Concurrent.Promise.Unsafe as UP
+import qualified Control.Concurrent.Promise as Promise
+import qualified Control.Concurrent.Async as Async
+import Control.Applicative
+import Control.Concurrent
+import Control.Exception
+import Data.Functor.Compose
+import qualified Streamly.Prelude as S
+
+action :: Int -> String -> Double -> IO ()
+action order name dur = do
+  -- delay a bit so that "Begin" gets printed in a consistent order
+  threadDelay $ 1000 * 10 * order
+  putStrLn $ "    Begin " <> name
+  threadDelay (floor $ 1000000 * dur)
+  putStrLn $ "    End " <> name
+  `onException` putStrLn ("    Killed " <> name)
+
+tester :: Applicative m => (m () -> IO ()) -> (IO () -> m ()) -> IO ()
+tester run lift = do
+  putStrLn "  Left:"
+  run $ (lift (action 0 "foo" 0.1) *> lift (action 1 "bar" 0.3)) *> lift (action 2 "baz" 0.2)
+  putStrLn "  Right:"
+  run $ lift (action 0 "foo" 0.1) *> (lift (action 1 "bar" 0.3) *> lift (action 2 "baz" 0.2))
+
+  putStrLn "  Left Error:"
+  try (run $ lift (fail "Fail") *> lift (action 0 "success" 0.1)) >>= print'
+  putStrLn "  Right Error:"
+  try (run $ lift (action 0 "success" 0.1) *> lift (fail "Fail")) >>= print'
+  where
+    print' :: Either SomeException () -> IO ()
+    print' = putStrLn . ("    "++) . show
+
+main :: IO ()
+main = do
+  putStrLn "oath timeout:"
+  Oath.evalOath $ Oath.oath (action 0 "delay" 1.0) <|> Oath.delay 200000
+  threadDelay 10000
+
+  putStrLn "oath: "
+  tester Oath.evalOath Oath.oath
+  putStrLn "async: "
+  tester Async.runConcurrently Async.Concurrently
+  putStrLn "futures:"
+  tester ((>>=Futures.block) . getCompose) (Compose . Futures.fork)
+
+  putStrLn "streamly:"
+  tester (S.drain . S.fromZipAsync . S.fromAhead) S.fromEffect
+
+  putStrLn "promise:"
+  tester Promise.runPromise Promise.liftIO
+
+  -- random
+  putStrLn "unsafe-promises:"
+  try (tester id UP.promise) >>= (print :: Either SomeException () -> IO ())
+
