diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2012 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/Pure.hs b/Yesod/Pure.hs
new file mode 100644
--- /dev/null
+++ b/Yesod/Pure.hs
@@ -0,0 +1,44 @@
+module Yesod.Pure
+    ( module Yesod
+    , module Yesod.Pure
+    ) where
+
+import Yesod
+import Data.Text (Text)
+import Data.Text.Lazy.Builder (fromText)
+import System.Log.FastLogger (Logger)
+
+type RouteParse master = [Text] -> Maybe (Route master)
+
+type RouteDispatch master = Text
+                         -> Route master
+                         -> Maybe (GHandler master master ChooseRep)
+
+handler :: HasReps a
+        => GHandler sub master a
+        -> Maybe (GHandler sub master ChooseRep)
+handler = Just . fmap chooseRep
+
+dispatch :: (YesodDispatch master master, Yesod master)
+         => RouteParse master
+         -> RouteDispatch master
+         -> Logger
+         -> master
+         -> master
+         -> (Route master -> Route master)
+         -> (Maybe (SessionBackend master) -> Application)
+         -> (Route master -> Maybe (SessionBackend master) -> Application)
+         -> Text
+         -> [Text]
+         -> Maybe (SessionBackend master)
+         -> Application
+dispatch parse dispatch' logger master sub toMaster on404 on405 method pieces session =
+    case parse pieces of
+        Just route ->
+            case dispatch' method route of
+                Just h -> yesodRunner logger h master sub (Just route) toMaster session
+                Nothing -> on405 route session
+        Nothing -> on404 session
+
+addCSS :: Text -> GWidget sub master ()
+addCSS = toWidget . const . CssBuilder . fromText
diff --git a/Yesod/Pure/NoRoute.hs b/Yesod/Pure/NoRoute.hs
new file mode 100644
--- /dev/null
+++ b/Yesod/Pure/NoRoute.hs
@@ -0,0 +1,95 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+-- | Create apps without any route data type. This loses some of the features
+-- of type-safe URLs, but simplifies app creation.
+module Yesod.Pure.NoRoute
+    ( module Yesod.Pure
+    , module Yesod.Pure.NoRoute
+    ) where
+
+import Yesod.Pure
+import Data.Text (Text)
+import Control.Applicative (Applicative (..), Alternative (..))
+import Data.Monoid (Monoid (..))
+
+data App = App (NoRouteDispatch ())
+
+instance YesodDispatch App App where
+    yesodDispatch logger master@(App (NoRouteDispatch d _)) sub toMaster on404 _ =
+        dispatch (Just . AppRoute) d' logger master sub toMaster on404 (const on404)
+      where
+        d' m (AppRoute ps) = d m ps
+
+instance RenderRoute App where
+    newtype Route App = AppRoute [Text]
+        deriving Eq
+    renderRoute (AppRoute x) = (x, [])
+
+data NoRouteDispatch a = NoRouteDispatch (Text -> [Text] -> Maybe (GHandler App App ChooseRep)) (Maybe a)
+
+instance Functor NoRouteDispatch where
+    fmap f (NoRouteDispatch x ma) = NoRouteDispatch x (fmap f ma)
+instance Applicative NoRouteDispatch where
+    pure = NoRouteDispatch (\_ _ -> Nothing) . Just
+    NoRouteDispatch a f <*> NoRouteDispatch b x =
+        NoRouteDispatch (\m p -> a m p <|> b m p) (f <*> x)
+instance Alternative NoRouteDispatch where
+    empty = NoRouteDispatch (\_ _ -> Nothing) Nothing
+    (<|>) = (*>)
+instance Monoid (NoRouteDispatch a) where
+    mempty = empty
+    mappend = (<|>)
+
+-- | I'm not convinced this instance is correct, for now consider it a dummy
+-- placeholder for playing around with do-syntax.
+instance Monad NoRouteDispatch where
+    return = pure
+    NoRouteDispatch f Nothing >>= _ = NoRouteDispatch f Nothing
+    NoRouteDispatch a (Just x) >>= f = NoRouteDispatch a (Just ()) *> f x
+
+serve :: HasReps a => GHandler App App a -> NoRouteDispatch ()
+serve h =
+    NoRouteDispatch go (Just ())
+  where
+    go _ [] = Just $ fmap chooseRep h
+    go _ _ = Nothing
+
+method :: Text -> NoRouteDispatch a -> NoRouteDispatch a
+method x (NoRouteDispatch f a) =
+    NoRouteDispatch go a
+  where
+    go m ps
+        | m == x = f m ps
+        | otherwise = Nothing
+
+static :: Text -> NoRouteDispatch a -> NoRouteDispatch a
+static x (NoRouteDispatch f a) =
+    NoRouteDispatch go a
+  where
+    go _ [] = Nothing
+    go m (t:ts)
+        | t == x = f m ts
+        | otherwise = Nothing
+
+dynamic :: PathPiece p => (p -> NoRouteDispatch b) -> NoRouteDispatch ()
+dynamic f =
+    NoRouteDispatch go (Just ())
+  where
+    go _ [] = Nothing
+    go m (t:ts) =
+        case fromPathPiece t of
+            Nothing -> Nothing
+            Just p ->
+                let (NoRouteDispatch f' _) = f p
+                 in f' m ts
+
+multi :: PathMultiPiece ps => (ps -> NoRouteDispatch b) -> NoRouteDispatch ()
+multi f =
+    NoRouteDispatch go (Just ())
+  where
+    go m ts =
+        case fromPathMultiPiece ts of
+            Nothing -> Nothing
+            Just ps ->
+                let (NoRouteDispatch f' _) = f ps
+                 in f' m []
diff --git a/yesod-pure.cabal b/yesod-pure.cabal
new file mode 100644
--- /dev/null
+++ b/yesod-pure.cabal
@@ -0,0 +1,26 @@
+name:                yesod-pure
+version:             0.1.0.0
+synopsis:            Yesod in pure Haskell: no Template Haskell or QuasiQuotes
+description:         Provides helper functions to simplify programming of Yesod without any code generation or non-Haskell DSLs. Mainly, this is focused on the routing quasi-quoter, though some templating help is provided as well.
+homepage:            https://github.com/snoyberg/yesod-pure
+license:             MIT
+license-file:        LICENSE
+author:              Michael Snoyman
+maintainer:          michael@snoyman.com
+category:            Web, Yesod
+build-type:          Simple
+cabal-version:       >=1.8
+homepage:            https://github.com/snoyberg/yesod-pure
+
+library
+  exposed-modules:     Yesod.Pure
+                       Yesod.Pure.NoRoute
+  build-depends:       base >= 4.5 && < 5
+                     , yesod >= 1.1
+                     , yesod-core >= 1.1.3
+                     , text >= 0.11
+                     , fast-logger
+
+source-repository head
+  type:     git
+  location: https://github.com/snoyberg/yesod-pure
