diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2008, Tupil
+
+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 Tupil 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/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/Text/Formlets.hs b/Text/Formlets.hs
new file mode 100644
--- /dev/null
+++ b/Text/Formlets.hs
@@ -0,0 +1,78 @@
+{-# LANGUAGE TypeOperators #-}
+module Text.Formlets ( module Text.Formlets.Form
+                     , input , password , inputF , passwordF,ensure
+                     , FailingForm, validate, runFormState, inputIntegerF
+                     , check, liftForm
+                     )
+                     where
+
+import Text.Formlets.Form
+import Control.Applicative
+import Control.Applicative.Compose
+import Control.Applicative.Error
+import Control.Applicative.State
+import Text.XHtml.Strict ((!))
+import qualified Text.XHtml.Strict as X
+
+-- | Apply a predicate to a value and return Success or Failure as appropriate
+ensure :: Show a 
+       => (a -> Bool) -- ^ The predicate
+       -> String      -- ^ The error message, in case the predicate fails
+       -> a           -- ^ The value
+       -> Failing a
+ensure p msg x | p x = Success x
+               | otherwise = Failure [msg]
+
+-- | Helper function for genereting input components based.
+input' :: (String -> String -> X.Html) -> Maybe String -> Form String
+input' i defaultValue = Form $ \env -> mkInput env <$> freshName
+   where mkInput :: Env -> String -> (Collector String, Xml)
+         mkInput env name = (`queryParam` name,
+                             i name (value name env))
+         value name env = maybe (maybe "" id defaultValue) id (lookup name env)
+
+-- | A form whose output may fail
+type FailingForm a = (Form :+: Failing) a
+
+runFormState :: Env             -- ^ A previously filled environment (may be empty)
+             -> FailingForm a   -- ^ The form
+             -> FormState       -- ^ Initial form state
+             -> ((Collector (Failing a), Xml), FormState)
+runFormState e f s = (runState (deform (decompose f) e) s)
+
+-- | Lifts a function on a Form to a function on a composed form.
+liftForm :: (Form (f a) -> Form (f a)) -> (Form :+: f) a -> (Form :+: f) a
+liftForm f = Compose . f . decompose
+
+-- | Lift a form component to a failing form component
+validate :: Form a -> FailingForm a
+validate f = Compose $ pure Success <*> f
+
+-- | Add additional validation to an already validated component
+check :: FailingForm a -> (a -> Failing b) -> FailingForm b
+check form f = decompose form `chk` checker f
+   where chk :: Form a -> (a -> Failing b) -> FailingForm b
+         chk form validator = Compose $ pure validator <*> form
+         checker :: (a -> Failing b) -> (Failing a -> Failing b)
+         checker f (Failure x) = Failure x
+         checker f (Success x) = f x
+
+-- | Component: an input field with an optional value
+input :: Maybe String -> Form String
+input = input' (\n v -> X.textfield n ! [X.value v])
+
+-- | Component: a password field with an optional value
+password :: Maybe String -> Form String
+password = input' (\n v -> X.password n ! [X.value v])
+
+-- | A trivially validated input component
+inputF :: Maybe String -> FailingForm String
+inputF = validate . input
+
+-- | A trivially validated password component
+passwordF :: Maybe String -> FailingForm String
+passwordF = validate . password
+
+-- | A validated integer component
+inputIntegerF :: Maybe Integer -> FailingForm Integer
+inputIntegerF x = validate (input $ fmap show x) `check` asInteger
diff --git a/Text/Formlets/Form.hs b/Text/Formlets/Form.hs
new file mode 100644
--- /dev/null
+++ b/Text/Formlets/Form.hs
@@ -0,0 +1,59 @@
+module Text.Formlets.Form where
+
+import Control.Applicative
+import Control.Applicative.State
+import Text.XHtml.Strict ((+++))
+import Text.XHtml.Strict as X
+
+type Env = [(String, String)]
+type FormState = Names
+type Names = Integer
+type Name = String
+type Xml = X.Html
+
+queryParam :: Env -> Name -> String
+queryParam env name = case (name `lookup` env) of
+                           Nothing -> error $ "Couldn't find " ++ name
+                           Just x  -> x
+
+newtype Form a = Form { deform :: Env -> State FormState (Collector a, X.Html) }
+
+instance Functor Form where
+  fmap f (Form a) = Form $ \env -> (fmap . fmapFst . fmap) f (a env)
+   where fmapFst f (a, b) = (f a, b)
+
+type Collector a = Env -> a
+
+instance Applicative Form where
+   pure = pureF
+   (<*>) = applyF
+
+pureF :: a -> Form a
+pureF v = Form $ \env -> pure (const v, X.noHtml) -- K
+
+applyF :: Form (a -> b) -> Form a -> Form b
+(Form f) `applyF` (Form v) = Form $ \env -> pure combine <*> f env <*> v env
+   where combine (f, x) (v, y) = (\e -> f e (v e), x +++ y)
+
+-- TODO ORYO
+freshName :: State FormState String
+freshName = do n <- get
+               put $ n + 1
+               return $ "input_" ++ show n
+
+currentName :: State FormState String
+currentName = gets $ (++) "input_" . show
+
+{- component: just some xml -}
+xml :: X.Html -> Form ()
+xml x = Form $ \env -> pure (const (), x)
+
+{- component: just some text -}
+text :: String -> Form ()
+text s = Form $ \env -> pure (const (), toHtml s)
+
+{- transform the XML component -}
+plug :: (Xml -> Xml) -> Form a -> Form a
+f `plug` (Form m) = Form $ \env -> pure plugin <*> m env
+   where plugin :: (a, Xml) -> (a, Xml)
+         plugin (c, x) = (c, f x)
diff --git a/formlets.cabal b/formlets.cabal
new file mode 100644
--- /dev/null
+++ b/formlets.cabal
@@ -0,0 +1,20 @@
+Name:            formlets
+Version:         0.1
+Synopsis:        Formlets implemented in Haskell
+Description:     A modular way to build forms based on applicative functors, as
+                 described in:
+                 .
+                  * Ezra Cooper, Samuel Lindley, Philip Wadler and Jeremy Yallop
+                    \"An idiom's guide to formlets\"
+                    Technical Report, EDI-INF-RR-1263.
+                    <http://groups.inf.ed.ac.uk/links/formlets/>
+Category:        XML, Web, User Interfaces, Text
+License:         BSD3
+License-file:    LICENSE
+Copyright:       (c) Jeremy Yallop / Tupil
+Author:          Jeremy Yallop / Chris Eidhof
+Maintainer:      Chris Eidhof <ce+hackage@tupil.com>
+Exposed-Modules:   Text.Formlets.Form
+                 , Text.Formlets
+Build-Type:      Simple
+Build-Depends:   base, haskell98, mtl, xhtml, applicative-extras
