diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2015 Matthijs Steen
+
+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/basex-client.cabal b/basex-client.cabal
new file mode 100644
--- /dev/null
+++ b/basex-client.cabal
@@ -0,0 +1,24 @@
+-- Initial basex-client.cabal generated by cabal init.  For further
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                basex-client
+version:             0.1.0.0
+synopsis:            A BaseX client for Haskell
+description:         A BaseX client library for Haskell that connects to the BaseX server using a socket. BaseX is a light-weight, high-performance and scalable XML Database written in Java.
+license:             MIT
+license-file:        LICENSE
+author:              Matthijs Steen
+maintainer:          matthijssteen1990@gmail.com
+-- copyright:
+category:            Database
+build-type:          Simple
+-- extra-source-files:
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     Example, AddExample, BaseXClient, CreateExample, QueryBindExample, QueryExample, BaseXClient.Session, BaseXClient.Query, BaseXClient.Utils
+  -- other-modules:
+  other-extensions:    NamedFieldPuns, LambdaCase
+  build-depends:       base >=4 && <5, network >=2.5 && <3, pureMD5 >=2 && <3, utf8-string >=1 && <2
+  hs-source-dirs:      src
+  default-language:    Haskell2010
diff --git a/src/AddExample.hs b/src/AddExample.hs
new file mode 100644
--- /dev/null
+++ b/src/AddExample.hs
@@ -0,0 +1,11 @@
+module AddExample where
+
+import BaseXClient
+
+main :: IO ()
+main = withSession "localhost" 1984 "admin" "admin" $ \session -> do
+  execute session "create db database" >>= print
+  add session "world/World.xml" "<x>Hello World!</x>" >>= print
+  add session "Universe.xml" "<x>Hello Universe!</x>" >>= print
+  execute session "xquery /" >>= print
+  execute session "drop db database" >>= print
diff --git a/src/BaseXClient.hs b/src/BaseXClient.hs
new file mode 100644
--- /dev/null
+++ b/src/BaseXClient.hs
@@ -0,0 +1,22 @@
+module BaseXClient (
+  module BaseXClient,
+  module BaseXClient.Query,
+  module BaseXClient.Session
+) where
+
+import qualified BaseXClient.Query as Query
+import BaseXClient.Query hiding (info, execute, close, sendCode, exec)
+import BaseXClient.Session hiding (sendInput)
+import Control.Exception
+import Network
+import System.IO
+
+executeQuery = Query.execute
+closeQuery = Query.close
+queryInfo = Query.info
+
+withSession :: String -> PortNumber -> String -> String -> (Handle -> IO a) -> IO a
+withSession host port user pass = bracket (connect host port user pass) close
+
+withQuery :: Handle -> String -> (Query -> IO a) -> IO a
+withQuery session q = bracket (query session q) closeQuery
diff --git a/src/BaseXClient/Query.hs b/src/BaseXClient/Query.hs
new file mode 100644
--- /dev/null
+++ b/src/BaseXClient/Query.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE NamedFieldPuns #-}
+module BaseXClient.Query where
+
+import BaseXClient.Utils hiding (exec)
+import qualified BaseXClient.Utils as Utils
+import Control.Applicative
+import System.IO
+
+data Query = Query {
+    session :: Handle,
+    ident :: String
+  }
+  deriving Show
+
+bind :: Query -> String -> String -> String -> IO String
+bind query name val ty = exec query 3 [name, val, ty]
+
+context :: Query -> String -> String -> IO String
+context query val ty = exec query 14 [val, ty]
+
+results :: Query -> IO [String]
+results Query{session, ident} = do
+  writeCode session 4
+  writeString session ident
+  result <- untilM (ok session) (readString session)
+  ok session >>= \b -> if b
+    then return result
+    else readString session >>= error
+
+execute, info, options, updating, close :: Query -> IO String
+execute = sendCode 5
+info = sendCode 6
+options = sendCode 7
+updating = sendCode 30
+close = sendCode 2
+
+sendCode :: Int -> Query -> IO String
+sendCode code query = exec query code []
+
+exec :: Query -> Int -> [String] -> IO String
+exec Query{session, ident} code strs = Utils.exec session code $ ident : strs
diff --git a/src/BaseXClient/Session.hs b/src/BaseXClient/Session.hs
new file mode 100644
--- /dev/null
+++ b/src/BaseXClient/Session.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE LambdaCase #-}
+module BaseXClient.Session where
+
+import BaseXClient.Utils
+import BaseXClient.Query (Query(..))
+import Control.Applicative
+import qualified Data.Digest.Pure.MD5 as MD5
+import Data.ByteString.Lazy.UTF8 (fromString)
+import Data.List
+import Network
+import System.IO
+
+data Result = Result {
+    content :: String,
+    info :: String
+  }
+  deriving Show
+
+connect :: String -> PortNumber -> String -> String -> IO Handle
+connect host port user pass = do
+  session <- connectTo host $ PortNumber port
+  hSetBuffering session $ BlockBuffering $ Just 4096
+  resp <- readString session
+  let (code, nonce) = case elemIndex ':' resp of
+        Just i -> let (realm, ':' : nonce') = splitAt i resp in
+          (intercalate ":" [user, realm, pass], nonce')
+        Nothing -> (pass, nonce)
+  writeStrings session [user, md5 $ md5 code ++ nonce]
+  ok session <$$> \b -> if b
+    then session
+    else error "Access denied."
+  where md5 = show . MD5.md5 . fromString
+
+execute :: Handle -> String -> IO Result
+execute session cmd = do
+  writeString session cmd
+  content <- readString session
+  info <- readString session
+  ok session <$$> \b -> if b
+    then Result{content, info}
+    else error info
+
+query :: Handle -> String -> IO Query
+query session q = do
+  ident <- exec session 0 [q]
+  return $ Query session ident
+
+create, add, replace, store :: Handle -> String -> String -> IO String
+create = sendInput 8
+add = sendInput 9
+replace = sendInput 12
+store = sendInput 13
+
+sendInput :: Int -> Handle -> String -> String -> IO String
+sendInput code session arg input = exec session code [arg, input]
+
+close :: Handle -> IO ()
+close session = do
+  writeString session "exit"
+  hClose session
diff --git a/src/BaseXClient/Utils.hs b/src/BaseXClient/Utils.hs
new file mode 100644
--- /dev/null
+++ b/src/BaseXClient/Utils.hs
@@ -0,0 +1,55 @@
+module BaseXClient.Utils where
+
+import Control.Applicative
+import Data.Char
+import System.IO
+
+exec :: Handle -> Int -> [String] -> IO String
+exec h code strs = do
+  writeCode h code
+  writeStrings h strs
+  info <- readString h
+  ok h <$$> \b -> if b
+    then info
+    else error info
+
+readString :: Handle -> IO String
+readString h = do
+  c <- hGetChar h
+  if c /= '\0'
+    then (:) <$> (if c == '\255' then hGetChar h else return c) <*> readString h
+    else return []
+
+writeCode :: Handle -> Int -> IO ()
+writeCode h code = hPutChar h $ chr code
+
+writeString :: Handle -> String -> IO ()
+writeString h str = do
+  writeString' h str
+  hFlush h
+
+writeStrings :: Handle -> [String] -> IO ()
+writeStrings h strs = do
+  mapM_ (writeString' h) strs
+  hFlush h
+
+writeString' :: Handle -> String -> IO ()
+writeString' h str = do
+  hPutStr h $ foldr (\c cs ->
+    if c == '\0' || c == '\255' then '\255' : c : cs else c : cs) [] str
+  hPutChar h '\0'
+
+ok :: Handle -> IO Bool
+ok h = ('\0' ==) <$> hGetChar h
+
+untilM :: IO Bool -> IO a -> IO [a]
+untilM test = whileM (not <$> test)
+
+whileM :: IO Bool -> IO a -> IO [a]
+whileM test body = test >>= \succeeds -> if succeeds
+    then (:) <$> body <*> whileM test body
+    else return []
+
+infixl 4 <$$>
+(<$$>) :: Functor f => f a -> (a -> b) -> f b
+(<$$>) = flip fmap
diff --git a/src/CreateExample.hs b/src/CreateExample.hs
new file mode 100644
--- /dev/null
+++ b/src/CreateExample.hs
@@ -0,0 +1,11 @@
+module CreateExample where
+
+import BaseXClient
+import System.CPUTime
+import Text.Printf
+
+main :: IO ()
+main = withSession "localhost" 1984 "admin" "admin" $ \session -> do
+  create session "database" "<x>Hello World!</x>" >>= print
+  execute session "xquery /" >>= print
+  execute session "drop db database" >>= print
diff --git a/src/Example.hs b/src/Example.hs
new file mode 100644
--- /dev/null
+++ b/src/Example.hs
@@ -0,0 +1,14 @@
+module Example where
+
+import BaseXClient
+import System.CPUTime
+import Text.Printf
+
+main :: IO ()
+main = do
+  start <- getCPUTime
+  withSession "localhost" 1984 "admin" "admin" $ \session ->
+    execute session "xquery 1 to 10" >>= print
+  end <- getCPUTime
+  let diff = fromIntegral (end - start) / (10 ^ 12)
+  printf "Computation time: %0.3f sec\n" (diff :: Double)
diff --git a/src/QueryBindExample.hs b/src/QueryBindExample.hs
new file mode 100644
--- /dev/null
+++ b/src/QueryBindExample.hs
@@ -0,0 +1,12 @@
+module QueryBindExample where
+
+import BaseXClient hiding (query)
+
+query :: String
+query = "declare variable $name external; for $i in 1 to 10 return element { $name } { $i }"
+
+main :: IO ()
+main = withSession "localhost" 1984 "admin" "admin" $ \session ->
+  withQuery session query $ \q -> do
+    bind q "name" "number" ""
+    executeQuery q >>= print
diff --git a/src/QueryExample.hs b/src/QueryExample.hs
new file mode 100644
--- /dev/null
+++ b/src/QueryExample.hs
@@ -0,0 +1,8 @@
+module QueryExample where
+
+import BaseXClient
+
+main :: IO ()
+main = withSession "localhost" 1984 "admin" "admin" $ \session ->
+  withQuery session "for $i in 1 to 10 return <xml>Text { $i }</xml>" $ \q ->
+    results q >>= print
