diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2014 Michael Snoyman, http://www.yesodweb.com/
+
+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/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/Yesod/WebSockets.hs b/Yesod/WebSockets.hs
new file mode 100644
--- /dev/null
+++ b/Yesod/WebSockets.hs
@@ -0,0 +1,124 @@
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+module Yesod.WebSockets
+    ( -- * Core API
+      WebSocketsT
+    , webSockets
+    , receiveData
+    , sendTextData
+    , sendBinaryData
+      -- * Conduit API
+    , sourceWS
+    , sinkWSText
+    , sinkWSBinary
+      -- * Async helpers
+    , race
+    , race_
+    , concurrently
+    , concurrently_
+    ) where
+
+import qualified Control.Concurrent.Async       as A
+import           Control.Monad                  (forever, void, when)
+import           Control.Monad.IO.Class         (MonadIO (liftIO))
+import           Control.Monad.Trans.Control    (control)
+import           Control.Monad.Trans.Control    (MonadBaseControl (liftBaseWith, restoreM))
+import           Control.Monad.Trans.Reader     (ReaderT (ReaderT, runReaderT))
+import qualified Data.Conduit                   as C
+import qualified Data.Conduit.List              as CL
+import qualified Network.Wai.Handler.WebSockets as WaiWS
+import qualified Network.WebSockets             as WS
+import qualified Yesod.Core                     as Y
+
+-- | A transformer for a WebSockets handler.
+--
+-- Since 0.1.0
+type WebSocketsT = ReaderT WS.Connection
+
+-- | Attempt to run a WebSockets handler. This function first checks if the
+-- client initiated a WebSockets connection and, if so, runs the provided
+-- application, short-circuiting the rest of your handler. If the client did
+-- not request a WebSockets connection, the rest of your handler will be called
+-- instead.
+--
+-- Since 0.1.0
+webSockets :: (Y.MonadBaseControl IO m, Y.MonadHandler m) => WebSocketsT m () -> m ()
+webSockets inner = do
+    req <- Y.waiRequest
+    when (WaiWS.isWebSocketsReq req) $
+        Y.sendRawResponse $ \src sink -> control $ \runInIO -> WaiWS.runWebSockets
+            WS.defaultConnectionOptions
+            (WaiWS.getRequestHead req)
+            (\pconn -> do
+                conn <- WS.acceptRequest pconn
+                runInIO $ runReaderT inner conn)
+            src
+            sink
+
+-- | Receive a piece of data from the client.
+--
+-- Since 0.1.0
+receiveData :: (MonadIO m, WS.WebSocketsData a) => WebSocketsT m a
+receiveData = ReaderT $ liftIO . WS.receiveData
+
+-- | Send a textual messsage to the client.
+--
+-- Since 0.1.0
+sendTextData :: (MonadIO m, WS.WebSocketsData a) => a -> WebSocketsT m ()
+sendTextData x = ReaderT $ liftIO . flip WS.sendTextData x
+
+-- | Send a binary messsage to the client.
+--
+-- Since 0.1.0
+sendBinaryData :: (MonadIO m, WS.WebSocketsData a) => a -> WebSocketsT m ()
+sendBinaryData x = ReaderT $ liftIO . flip WS.sendBinaryData x
+
+-- | A @Source@ of WebSockets data from the user.
+--
+-- Since 0.1.0
+sourceWS :: (MonadIO m, WS.WebSocketsData a) => C.Producer (WebSocketsT m) a
+sourceWS = forever $ Y.lift receiveData >>= C.yield
+
+-- | A @Sink@ for sending textual data to the user.
+--
+-- Since 0.1.0
+sinkWSText :: (MonadIO m, WS.WebSocketsData a) => C.Consumer a (WebSocketsT m) ()
+sinkWSText = CL.mapM_ sendTextData
+
+-- | A @Sink@ for sending binary data to the user.
+--
+-- Since 0.1.0
+sinkWSBinary :: (MonadIO m, WS.WebSocketsData a) => C.Consumer a (WebSocketsT m) ()
+sinkWSBinary = CL.mapM_ sendBinaryData
+
+-- | Generalized version of 'A.race'.
+--
+-- Since 0.1.0
+race :: MonadBaseControl IO m => m a -> m b -> m (Either a b)
+race x y = liftBaseWith (\run -> A.race (run x) (run y))
+    >>= either (fmap Left . restoreM) (fmap Right . restoreM)
+
+-- | Generalized version of 'A.race_'.
+--
+-- Since 0.1.0
+race_ :: MonadBaseControl IO m => m a -> m b -> m ()
+race_ x y = void $ race x y
+
+-- | Generalized version of 'A.concurrently'. Note that if your underlying
+-- monad has some kind of mutable state, the state from the second action will
+-- overwrite the state from the first.
+--
+-- Since 0.1.0
+concurrently :: MonadBaseControl IO m => m a -> m b -> m (a, b)
+concurrently x y = do
+    (resX, resY) <- liftBaseWith $ \run -> A.concurrently (run x) (run y)
+    x' <- restoreM resX
+    y' <- restoreM resY
+    return (x', y')
+
+-- | Run two actions concurrently (like 'A.concurrently'), but discard their
+-- results and any modified monadic state.
+--
+-- Since 0.1.0
+concurrently_ :: MonadBaseControl IO m => m a -> m b -> m ()
+concurrently_ x y = void $ liftBaseWith $ \run -> A.concurrently (run x) (run y)
diff --git a/yesod-websockets.cabal b/yesod-websockets.cabal
new file mode 100644
--- /dev/null
+++ b/yesod-websockets.cabal
@@ -0,0 +1,30 @@
+-- Initial yesod-websockets.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                yesod-websockets
+version:             0.1.0.0
+synopsis:            WebSockets support for Yesod
+description:         WebSockets support for Yesod
+homepage:            https://github.com/yesodweb/yesod
+license:             MIT
+license-file:        LICENSE
+author:              Michael Snoyman
+maintainer:          michael@snoyman.com
+category:            Web
+build-type:          Simple
+cabal-version:       >=1.8
+
+library
+  exposed-modules:     Yesod.WebSockets
+  build-depends:       base              >= 4.5 && < 5
+                     , wai-websockets    >= 2.1
+                     , websockets        >= 0.8
+                     , transformers      >= 0.2
+                     , yesod-core        >= 1.2.7
+                     , monad-control     >= 0.3
+                     , conduit           >= 1.0.15.1
+                     , async             >= 2.0.1.5
+
+source-repository head
+  type:     git
+  location: https://github.com/yesodweb/yesod
