diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2014 Irek Jozwiak
+
+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/bdd.cabal b/bdd.cabal
new file mode 100644
--- /dev/null
+++ b/bdd.cabal
@@ -0,0 +1,38 @@
+Name:                bdd
+Version:             0.1.0.0
+Synopsis:            Behavior-Driven Development DSL
+Homepage:            http://github.com/humane-software/haskell-bdd
+License:             MIT
+License-File:        LICENSE
+Author:              Irek Jozwiak, Pavlo Kerestey
+Maintainer:          irek@humane.software
+Category:            Testing
+Stability:           experimental
+Build-Type:          Simple
+Cabal-Version:       >=1.10
+Description:         A domain-specific language for testing programs using Behavior-Driven Development (BDD) process.
+
+extra-source-files:
+  changelog.md
+
+Library
+  exposed-modules:     Test.Bdd, Test.Bdd.Internal
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+  build-depends:       base ==4.*
+                      ,HUnit
+                      ,mtl
+                      ,transformers
+  
+Test-Suite system-tests
+  type:       exitcode-stdio-1.0
+  other-modules:       BddTest
+  main-is:    SystemTests.hs
+  hs-source-dirs: tests/system, src
+  build-depends: base
+                ,directory
+                ,HUnit
+                ,mtl
+                ,process
+                ,test-framework
+                ,test-framework-hunit
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,3 @@
+0.1.0.0
+
+* Initial version
diff --git a/src/Test/Bdd.hs b/src/Test/Bdd.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/Bdd.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE BangPatterns, ExistentialQuantification, FlexibleContexts, ImpredicativeTypes, Rank2Types, ScopedTypeVariables #-}
+module Test.Bdd (
+  (^?=)
+ ,Given
+ ,Then
+ ,When
+ ,andAfter_
+ ,expectError_
+ ,given_
+ ,noError
+ ,testThat
+ ,then_
+ ,when_
+ ) where
+
+import Control.Monad.Error.Class
+import Test.Bdd.Internal
+import Test.HUnit ((@?=))
+
+type Given m a = Monad m => m a
+
+type When m a = Monad m => m a
+
+type Then m a = Monad m => a -> m ()
+
+testThat :: GivenWithTeardown m
+testThat = []
+
+infixl 1 `given_`, `when_`, `then_`
+infixl 2 `andAfter_`
+
+given_ :: (StorableAsGivenWithTeardown m g,Monad m) => GivenWithTeardown m -> g -> GivenWithTeardown m
+given_ gs g = gs ++ mkGiven g
+
+andAfter_ :: m a -> (a -> m ()) -> (m a, a -> m ())
+andAfter_ = (,)
+
+when_ :: Monad m => GivenWithTeardown m -> When m b -> m b
+when_ (GivenStore (g,t):gs) w = do
+  v <- g
+  res <- when_ gs w
+  t v
+  return res
+when_ [] w = w
+
+then_ :: When m a -> Then m a -> When m a
+then_ !w t = w >>= (\res-> (t $! res) >> return res)
+
+expectError_ :: MonadError e m => When m a -> Then m e -> When m ()
+expectError_ w t = (w >> fail "expected exception was not thrown") `catchError` (\e->t e)
+
+noError :: Then m a
+noError = const (return ())
+
+(^?=) :: (Eq a, Show a) => IO a -> a -> b -> IO ()
+actualF ^?= expected = (\_->actualF >>= (@?= expected))
diff --git a/src/Test/Bdd/Internal.hs b/src/Test/Bdd/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/Bdd/Internal.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE ExistentialQuantification, FlexibleInstances, MultiParamTypeClasses, Rank2Types #-}
+
+module Test.Bdd.Internal (
+  GivenStore(..)
+ ,GivenWithTeardown
+ ,StorableAsGivenWithTeardown(..)
+ ) where
+
+data GivenStore m = forall a. GivenStore (m a, a -> m ())
+
+type GivenWithTeardown m = Monad m => [GivenStore m]
+
+class StorableAsGivenWithTeardown m g where
+  mkGiven :: g -> GivenWithTeardown m
+
+instance StorableAsGivenWithTeardown m (m a) where
+  mkGiven g = [GivenStore (g,const (return ()))]
+
+instance StorableAsGivenWithTeardown m (m a, a -> m ()) where
+  mkGiven = return . GivenStore
diff --git a/tests/system/BddTest.hs b/tests/system/BddTest.hs
new file mode 100644
--- /dev/null
+++ b/tests/system/BddTest.hs
@@ -0,0 +1,83 @@
+{-# LANGUAGE FlexibleContexts,RankNTypes,ScopedTypeVariables #-}
+
+module BddTest (tests) where
+
+import Control.Applicative ((<$>))
+import Control.Arrow ((>>>))
+import Control.Monad (when)
+import Control.Exception
+import Control.Monad.Writer
+import System.Directory
+import System.Process (runCommand)
+import Test.Bdd
+import Test.Bdd.Internal
+import Test.HUnit
+
+tests = test [
+
+  "the most rudimentary construct (doesn't test anything yet)" ~:
+    let runSomeImaginaryIOAction :: IO ()
+        runSomeImaginaryIOAction = return ()
+    in TestCase $
+      testThat
+      `when_` runSomeImaginaryIOAction
+
+ ,"assert something" ~: do
+    testThat
+      `when_` writeFile "/tmp/BddTestFile" "xxx"
+      `then_` readFile "/tmp/BddTestFile" ^?= "xxx"
+    -- we'll explain how to teardown later
+    void (runCommand "rm -f /tmp/BddTestFile")
+
+ ,"multiple thens are possible" ~: do
+    testThat
+      `when_` writeFile "/tmp/BddTestFile" "xxx"
+      `then_` readFile "/tmp/BddTestFile" ^?= "xxx"
+      `then_` (elem "BddTestFile" <$> getDirectoryContents "/tmp/") ^?= True
+    -- we'll explain how to teardown later
+    void (runCommand "rm -f /tmp/BddTestFile")
+
+ ,"preconditions are possible as givens" ~:
+    let noFile :: FilePath -> Given IO ()
+        noFile f = doesFileExist f >>= \b-> when b (removeFile f)
+    in do
+      testThat
+        `given_` noFile "/tmp/BddTestFile"
+        `when_` writeFile "/tmp/BddTestFile" "xxx"
+        `then_` readFile "/tmp/BddTestFile" ^?= "xxx"
+      -- we'll explain how to teardown later
+      void (runCommand "rm -f /tmp/BddTestFile")
+
+ -- TODO: to be implemented
+ -- ,"given can have a teardown, it takes given's return value" ~:
+ --    let directory :: FilePath -> Given IO FilePath
+ --        directory f = removeDir f >> createDirectory f >> return f
+ --        removeDir :: FilePath -> IO ()
+ --        removeDir f = doesDirectoryExist f >>= \exists->
+ --                      when exists (removeDirectoryRecursive f)
+ --    in testThat
+ --      `given_` directory "/tmp/BddTestDir" `andAfter_` removeDir
+ --      `when_` writeFile "/tmp/BddTestDir/test" "xxx"
+ --      `then_` readFile "/tmp/BddTestDir/test" ^?= "xxx"
+
+ -- ,"order of execution" ~:
+ --    execWriter (
+ --      (testThat::GivenWithTeardown (Writer [String]))
+ --      `given_` (tell ["given"]::Writer [String] ()) `andAfter_` const (tell ["teardown"])
+ --      `when_` tell ["when"]
+ --      `then_` const (tell ["then"])
+ --     ) @?= ["given","when","then","teardown"]
+
+ ,"can expect an error" ~:
+    testThat
+    `when_` readFile "/that_surely_not_exists"
+    `expectError_` (show >>> (@?= "/that_surely_not_exists: openFile: does not exist (No such file or directory)"))
+
+ ,"test will fail if expected exception not thrown" ~:
+    (do
+       testThat
+         `when_` readFile "/etc/passwd"
+         `expectError_` (show >>> (@?= "this will never be thrown"))
+       fail "should fail but didn't"
+     ) `catch` (\(e::SomeException)->assertBool "expectError did not fail" (show e /= "user error (should fail but didn't)"))
+ ]
diff --git a/tests/system/SystemTests.hs b/tests/system/SystemTests.hs
new file mode 100644
--- /dev/null
+++ b/tests/system/SystemTests.hs
@@ -0,0 +1,10 @@
+module Main where
+
+import qualified BddTest
+import Control.Monad (void)
+import Test.Framework
+import Test.Framework.Providers.HUnit
+import Test.HUnit
+
+main :: IO ()
+main = defaultMain (hUnitTestToTests BddTest.tests)
