diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,31 @@
+Copyright (c) 2011, Jinjing Wang
+
+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 Jinjing Wang 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.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,4 @@
+#! /usr/bin/env runhaskell
+
+> import Distribution.Simple
+> main = defaultMain
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,4 @@
+2011.6.10
+---------
+
+* init
diff --git a/hack2.cabal b/hack2.cabal
new file mode 100644
--- /dev/null
+++ b/hack2.cabal
@@ -0,0 +1,24 @@
+Name:                 hack2
+Version:              2011.6.10
+Build-type:           Simple
+Synopsis:             a Haskell Webserver Interface (V2)
+Description:
+        
+    Hack2: a Haskell Webserver Interface (V2)
+
+License:              BSD3
+License-file:         LICENSE
+Author:               Jinjing Wang
+Maintainer:           Jinjing Wang <nfjinjing@gmail.com>
+Build-Depends:        base
+Cabal-version:        >= 1.2
+category:             Web
+homepage:             https://github.com/nfjinjing/hack2
+data-files:           readme.md, changelog.md
+
+library
+  ghc-options: -Wall
+  build-depends: base >= 3 && < 5, data-default >= 0.2, bytestring
+  hs-source-dirs: src/
+  exposed-modules:  
+                    Hack2
diff --git a/readme.md b/readme.md
new file mode 100644
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,189 @@
+Hack2: a Haskell Webserver Interface (V2)
+========================================
+
+Hack2 is a port of Ruby's [Rack](http://rack.rubyforge.org/) webserver interface.
+
+Version
+-------
+
+> 2011.6.10
+
+Introduction
+------------
+
+### Idea
+
+Separation of concerns:
+
+* hack2: interface spec
+* hack2-middleware: building blocks
+* hack2-handler: server backends
+
+### Design
+
+    type Application = Env -> IO Response
+
+### Demo
+
+    {-# LANGUAGE OverloadedStrings #-}
+
+    import Hack2
+
+    app :: Application
+    app = \env -> return $
+      Response 200 [ ("Content-Type", "text/plain") ] "Hello World"
+    
+
+Spec
+----
+
+### The Environment
+
+* __requestMethod__: The HTTP request method, e.g. `GET`, `POST`.
+* __scriptName__: The initial portion of the request URL‘s “path” that corresponds to the application object, so that the application knows its virtual “location”. This may be an empty string, if the application corresponds to the “root” of the server.
+* __pathInfo__: The remainder of the request URL‘s “path”, designating the virtual “location” of the request‘s target within the application. This may be an empty string, if the request URL targets the application root and does not have a trailing slash. This value may be percent-encoded when I originating from a URL.
+* __queryString__: The portion of the request URL that follows the ?, if any. May be empty.
+* __serverName, serverPort__: When combined with scriptName and pathInfo, these variables can be used to complete the URL. Note, however, that `Host` in http field, if present, should be used in preference to serverName for reconstructing the request URL. serverName and serverPort can never be empty, and so are always required.
+* __httpHeaders__: Variables corresponding to the client-supplied HTTP request headers (e.g. "Accept"). The presence or absence of these variables should correspond with the presence or absence of the appropriate HTTP header in the request. 
+* __hackVersion__: The list of `Int`, representing this version of Hack
+* __hackUrlScheme__: `HTTP` or `HTTPS`, depending on the request URL. 
+* __hackInput__: The body of the request.
+* __hackErrors__: The error stream.
+* __hackHeaders__: None standard http headers.
+
+
+### The Response
+
+* __status__: This is an HTTP status. It must be greater than or equal to 100. 
+* __headers__: The header must not contain a Status key, contain keys with : or newlines in their name, contain keys names that end in - or _, but only contain keys that consist of letters, digits, _ or - and start with a letter. The values of the header must be Strings, consisting of lines (for multiple header values) separated by “\n”. The lines must not contain characters below 037.
+* __body__: The body of the response.
+
+### Properties
+
+* The __scriptName__, if non-empty, must start with /
+* The __pathInfo__, if non-empty, must start with /
+* One of __scriptName__ or __pathInfo__ must be set. __pathInfo__ should be / if __scriptName__ is empty. __scriptName__ never should be /, but instead be empty.
+
+
+1 minute tutorial
+-----------------
+
+### update cabal
+
+    cabal update
+    
+### install hack
+
+    cabal install hack2
+
+### pick a backend
+
+    cabal install hack2-handler-happstack
+
+### Create a Hack app
+
+put the following code in `Main.hs`
+
+    {-# LANGUAGE OverloadedStrings #-}
+
+    import Hack2
+    import Hack2.Handler.HappstackServer
+
+    app :: Application
+    app = \env -> return $ Response 
+        { status  = 200
+        , headers = [ ("Content-Type", "text/plain") ]
+        , body    = "Hello World"
+        }
+
+    main = run app
+
+
+### run
+
+    runghc Main.hs
+
+It should be running on [http://127.0.0.1:3000](http://127.0.0.1:3000) now.
+
+Middleware
+-----------
+
+(below is waiting to be finished)
+------------------------------------------
+
+
+### demo usage of middleware
+
+install hack-contrib:
+
+    cabal install hack-contrib
+
+put the following in `Main.hs`. This code uses the `URLMap` middleware to route both `/hello` and `/there` to the `say` application.
+
+    import Hack
+    import Hack.Handler.HappstackServer
+    import Hack.Contrib.Utils
+    import Hack.Contrib.Middleware.URLMap
+    import Data.ByteString.Lazy.Char8 (pack)
+    import Data.Default
+    
+    say :: Application
+    say = \env -> return $ def {body = pack $ show env, status = 200}
+
+    app :: Application
+    app = url_map [("/hello", say), ("/there", say)] empty_app
+
+    main = run app
+
+### create a middleware
+
+inside Hack.hs:
+
+    type Middleware = Application -> Application
+
+since Haskell has curry, middleware api can be of type
+
+    Anything -> Application -> Application
+
+just pass an applied middleware into a chain.
+
+finally the source code of `Config.hs`:
+
+    module Hack.Contrib.Middleware.Config (config) where
+
+    import Hack
+
+    config :: (Env -> Env) -> Middleware
+    config alter app = \env -> app (alter env)
+
+
+### Use the middleware stack
+
+From `Hack.Contrib.Utils`:
+
+    -- usage: use [content_type, cache] app
+    use :: [Middleware] -> Middleware
+    use = reduce (<<<)
+
+Handlers
+--------
+
+Once an application is written using Hack, it should work on any web server that provides a Hack handler.
+
+A handler should expose at least one function of type:
+
+    run :: Application -> IO ()
+
+Upgrade
+-------
+
+With every new release, any library links to hack should be recompiled against the new version, usually as simple as:
+
+    cabal install linked_lib --reinstall
+
+Links
+-----
+
+### [Discuss:Web programming with Haskell](http://www.haskell.org/mailman/listinfo/web-devel)
+
+
diff --git a/src/Hack2.hs b/src/Hack2.hs
new file mode 100644
--- /dev/null
+++ b/src/Hack2.hs
@@ -0,0 +1,90 @@
+module Hack2 where
+
+import Data.Default (def, Default)
+import System.IO (stderr)
+
+import Data.ByteString.Lazy (ByteString)
+import qualified Data.ByteString.Lazy as B
+
+type Application = Env -> IO Response
+type Middleware  = Application -> Application
+
+data RequestMethod =
+     OPTIONS
+  |  GET
+  |  HEAD
+  |  POST
+  |  PUT
+  |  DELETE
+  |  TRACE
+  |  CONNECT
+  deriving (Show, Read, Eq)
+
+data HackUrlScheme = HTTP | HTTPS deriving (Show, Read, Eq)
+
+newtype HackErrors = HackErrors { unHackErrors :: ByteString -> IO () }
+
+instance Show HackErrors where
+  show _ = "HackErrors"
+
+instance Default HackErrors where
+  def = HackErrors (B.hPutStr stderr)
+
+instance Eq HackErrors where
+  _ == _ = True
+
+data Env = Env 
+  {  requestMethod  :: RequestMethod
+  ,  scriptName     :: ByteString
+  ,  pathInfo       :: ByteString
+  ,  queryString    :: ByteString
+  ,  serverName     :: ByteString
+  ,  serverPort     :: Int
+  ,  httpHeaders    :: [(ByteString, ByteString)]
+  ,  hackVersion    :: (Int, Int, Int)
+  ,  hackUrlScheme  :: HackUrlScheme
+  ,  hackInput      :: ByteString
+  ,  hackErrors     :: HackErrors
+  ,  hackHeaders    :: [(ByteString, ByteString)]
+  }
+  deriving (Show, Eq)
+
+data Response = Response
+  {  status   :: Int
+  ,  headers  :: [(ByteString, ByteString)]
+  ,  body     :: ByteString
+  }
+  deriving (Show, Eq)
+
+instance Default RequestMethod where
+  def = GET
+
+instance Default HackUrlScheme where
+  def = HTTP
+
+instance Default Response where
+  def = Response 
+    {
+      status  = 200
+    , headers = []
+    , body    = B.empty
+    }
+
+instance Default Env where
+  def = Env 
+    {
+        requestMethod = def
+      , scriptName    = B.empty
+      , pathInfo      = B.empty
+      , queryString   = B.empty
+      , serverName    = B.empty
+      , serverPort    = def
+      , httpHeaders   = def
+      , hackVersion   = currentVersion
+      , hackUrlScheme = def
+      , hackInput     = B.empty
+      , hackErrors    = def
+      , hackHeaders   = def
+    }
+    where
+      currentVersion = (2011, 6, 10)
