diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2015, Scrive
+
+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 Gracjan Polak 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/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# kontra-config [![Hackage version](https://img.shields.io/hackage/v/kontra-config.svg?label=Hackage)](https://hackage.haskell.org/package/kontra-config) [![Build Status](https://secure.travis-ci.org/scrive/kontra-config.svg?branch=master)](http://travis-ci.org/scrive/kontra-config)
+
+A library for reading JSON configuration files. Based on unjson.
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/kontra-config.cabal b/kontra-config.cabal
new file mode 100644
--- /dev/null
+++ b/kontra-config.cabal
@@ -0,0 +1,38 @@
+name:                kontra-config
+version:             0.1
+synopsis:            JSON config file parsing based on unjson
+description:         A library for reading JSON configuration files. Based on unjson.
+homepage:            https://github.com/scrive/kontra-config
+license:             BSD3
+license-file:        LICENSE
+author:              Scrive AB
+maintainer:          Gracjan Polak <gracjan@scrive.com>, Jonathan Jouty <jonathan@scrive.com>, Mikhail Glushenkov <mikhail@scrive.com>
+copyright:           Scrive AB
+category:            Data
+build-type:          Simple
+cabal-version:       >=1.10
+extra-source-files:  README.md
+tested-with:         GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.1
+
+source-repository head
+  type:     git
+  location: https://github.com/scrive/kontra-config
+
+library
+  exposed-modules:     Configuration
+
+  build-depends:       base < 5
+                     , transformers-base
+                     , data-default
+                     , exceptions >= 0.6
+                     , bytestring
+                     , utf8-string
+                     , text
+                     , unjson
+                     , yaml
+
+  hs-source-dirs:      src
+
+  default-language:    Haskell2010
+  default-extensions:  FlexibleContexts
+                     , ScopedTypeVariables
diff --git a/src/Configuration.hs b/src/Configuration.hs
new file mode 100644
--- /dev/null
+++ b/src/Configuration.hs
@@ -0,0 +1,87 @@
+module Configuration (
+    readConfig
+  ) where
+
+import Control.Monad.Base
+import Control.Monad.Catch
+import Data.Default
+import Data.Unjson
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as BSL
+import qualified Data.ByteString.Lazy.UTF8 as BSL (toString)
+import qualified Data.Text as Text
+import qualified Data.Yaml as Yaml
+
+--
+-- Error handling here:
+-- 1. When no file: please create file and full docs
+-- 2. When looks like json but not parse as json: info where it did not parse, no other info
+-- 3. When does not look like json and does not readIO: full docs
+-- 4. When unjson has issue, then just info about specific problems
+
+readConfig :: forall a m . (Unjson a, Default a, MonadBase IO m, MonadCatch m) => (String -> m ()) -> FilePath -> m a
+readConfig logger path = do
+  logger $ "Reading configuration " ++ path ++ "..."
+  bsl' <- either logExceptionAndPrintFullDocs return
+    =<< try (liftBase (BSL.readFile path))
+
+  let bsl = BSL.dropWhile (`elem` [10,13,32]) bsl'
+
+  res <- do
+      js <- either logYamlParseExceptionAndBlameJsonParser return $
+            Yaml.decodeEither' (BS.concat (BSL.toChunks bsl))
+      case parse ud js of
+        Result value [] -> return value
+        Result _ problems -> logProblems problems
+
+  logger $ "Configuration file " ++ path ++ " read and parsed."
+  return res
+  where
+    ud :: UnjsonDef a
+    ud = unjsonDef
+    logStringAndFail :: String -> m g
+    logStringAndFail ex = do
+      logger $ ex
+      fail ex
+    logYamlParseExceptionAndBlameJsonParser :: Yaml.ParseException -> m g
+    logYamlParseExceptionAndBlameJsonParser ex = do
+      -- sadly parsing issues in aeson as reported as badly as anything else
+      logStringAndBlameJsonParser $ showNiceYamlParseException path ex
+    logStringAndBlameJsonParser :: String -> m g
+    logStringAndBlameJsonParser ex = do
+      -- sadly parsing issues in aeson as reported as badly as anything else
+      logger $ ex
+      logStringAndFail $ "Configuration file '" ++ path ++ "' has syntax errors and is not a valid json"
+    logExceptionAndPrintFullDocs :: SomeException -> m g
+    logExceptionAndPrintFullDocs ex = logStringAndPrintFullDocs (show ex)
+    logStringAndPrintFullDocs :: String -> m g
+    logStringAndPrintFullDocs ex = do
+      logger $ ex ++ "\n" ++ render ud ++ "\n" ++ configAsJsonString def
+      fail (show ex)
+    logProblem (Anchored xpath msg) = do
+        case renderForPath xpath ud of
+          Just moreInfo -> do
+            logger $ show xpath ++ ": " ++ Text.unpack msg ++ "\n" ++ moreInfo
+          Nothing -> do
+            logger $ show xpath ++ ": " ++ Text.unpack msg
+    logProblems problems = do
+      logger $ "There were issues with the content of configuration " ++ path
+      mapM_ logProblem problems
+      fail $ "There were issues with the content of configuration " ++ path
+    configAsJsonString :: a -> String
+    configAsJsonString a = BSL.toString $ unjsonToByteStringLazy' (Options { pretty = True, indent = 4, nulls = False }) ud a
+
+showNiceYamlParseException :: FilePath -> Yaml.ParseException -> String
+showNiceYamlParseException filepath parseException =
+  case parseException of
+    Yaml.NonScalarKey -> filepath ++ ": non scalar key"
+    Yaml.UnknownAlias anchorName -> filepath ++ ": unknown alias " ++ anchorName
+    Yaml.UnexpectedEvent received expected -> filepath ++ ": unknown event received " ++ show received ++ " when expected " ++ show expected
+    Yaml.InvalidYaml Nothing -> filepath ++ ": invalid yaml (no further info available)"
+    Yaml.InvalidYaml (Just (Yaml.YamlException ex)) -> filepath ++ ": invalid yaml: " ++ ex
+    Yaml.InvalidYaml (Just (Yaml.YamlParseException problem context (Yaml.YamlMark _index line column))) ->
+      filepath ++ ":" ++ show (line+1) ++ ":" ++ show (column+1) ++ ": " ++ problem ++ " " ++ context
+    Yaml.AesonException ex -> filepath ++ ": " ++ ex
+    Yaml.OtherParseException ex -> filepath ++ ": " ++ show ex
+    Yaml.NonStringKeyAlias anchorName value -> filepath ++ ": unknown non-string key alias " ++ show anchorName ++ ", " ++ show value
+    Yaml.CyclicIncludes -> filepath ++ ": cyclic includes"
