diff --git a/CHANGES.md b/CHANGES.md
new file mode 100644
--- /dev/null
+++ b/CHANGES.md
@@ -0,0 +1,9 @@
+Changelog / Release Notes
+=========================
+
+Version 0.1.0.0
+---------------
+
+Release date: **2015-11-09**
+
+* First public release.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2015, Matej Kollar
+
+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 Matej Kollar 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,112 @@
+Picky JSON Parser
+=================
+
+JSON parser with nice error messages and little
+more strict syntax (whitespace-wise). Based on
+[Aeson](http://hackage.haskell.org/package/aeson) and
+[Parsec](http://hackage.haskell.org/package/parsec).
+
+Interacting with user
+---------------------
+
+JSON being nice readable text-based format seems good candidate
+for occasionally being created by a user. While Aeson provides really
+super-optimized parsers, their error messages are not very helpful.
+Creating larger JSON object by hand can be frustrating (especially)
+when you make even a small mistake.
+
+While this parser is not optimized for speed, it tries to produce
+nice and helpful error messages. (This library uses Parsec library.)
+
+Another way to help your user is not allowing him or her to
+learn wrong habbits. Just look at the following piece of code (be
+warned - there are trailing spaces there):
+
+~~~ .json
+{ "name"   :   
+   ,   
+
+"Hal"
+}
+~~~
+
+That (in my opinion) is something one would not like to see in files
+users of his or hers tool produces. So why not forbid that? This
+library does not allow such things while still allowing to make
+the input more airy.
+
+Composability
+-------------
+
+This library was written with re-usability in mind. Parsers it
+provides do not consume any spaces before of after corresponding
+values and therefore are more easily reusable for your own projects.
+
+Parsing to Aeson data types
+---------------------------
+
+Aeson library is nice to work with with large ecosystem of useful
+libraries. So why not join them and avoid reinventing the wheel?
+
+Example Use
+-----------
+
+### Script
+
+~~~ { .haskell }
+{-# LANGUAGE DeriveGeneric #-}
+module Main (main) where
+
+import GHC.Generics
+import System.Environment (getArgs)
+
+import Data.Aeson hiding (eitherDecode)
+import Data.Aeson.Parser.Parsec.Picky (eitherDecode)
+
+import Data.Text.IO as Text (readFile)
+
+data Contact = Contact
+    { name :: String
+    , address :: String
+    } deriving (Generic, Show)
+
+instance FromJSON Contact where
+
+printContacts :: [Contact] -> IO ()
+printContacts = mapM_ print
+
+main' :: [String] -> IO ()
+main' [filename] = Text.readFile filename
+    >>= process . eitherDecode filename
+    where
+    process = either putStrLn printContacts
+main' _ = print "Usage: script [CONTACTS_FILE]"
+
+main :: IO ()
+main = getArgs >>= main'
+~~~
+
+### Input file
+
+~~~ { .json }
+[ { "name": "Alice"
+  , "address": "Kansas"
+  }
+]
+~~~
+
+Motivation
+----------
+
+Why another JSON parser? Some internal tool for
+JSON RPC testing used simple format that re-used JSON parsers.
+It was already re-written few times and reasons were:
+
+* Bad error messages for people who were writing testing scripts.
+* Those people were able to do horrible stuff (trailing spaces, ...).
+* Some parsers that used Parsec (and produced helpful error messages)
+  were producing non-aeson data structures and we already use
+  aeson on some places so we had option to be more heterogeneous
+  or make useless conversions.
+
+No parser I was aware of seemed to solve these issues.
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/aeson-parsec-picky.cabal b/aeson-parsec-picky.cabal
new file mode 100644
--- /dev/null
+++ b/aeson-parsec-picky.cabal
@@ -0,0 +1,82 @@
+name:                aeson-parsec-picky
+
+-- The package version.  See the Haskell package versioning policy (PVP)
+-- for standards guiding when and how versions should be incremented.
+-- http://www.haskell.org/haskellwiki/Package_versioning_policy
+-- PVP summary:     +-+------- breaking API changes
+--                  | | +----- non-breaking API additions
+--                  | | | +--- code changes with no API change
+version:            0.1.0.0
+
+-- A short (one-line) description of the package.
+synopsis:           Alternative JSON parser based on Parsec and Aeson
+
+-- A longer description of the package.
+description:        JSON parser with nice error messages and
+                    little more strict syntax (whitespace-wise).
+homepage:           https://github.com/FPBrno/aeson-parsec-picky
+
+-- The license under which the package is released.
+license:            BSD3
+
+-- The file containing the license text.
+license-file:       LICENSE
+
+-- The package author(s).
+author:             Matej Kollar
+
+-- An email address to which users can send suggestions, bug reports, and
+-- patches.
+maintainer:         208115@mail.muni.cz
+
+-- A copyright notice.
+copyright:          (c) 2015, Matej Kollar
+
+category:           Text, JSON
+
+build-type:         Simple
+
+-- Extra files to be distributed with the package, such as examples or a
+-- README.
+extra-source-files:   README.md
+                    , CHANGES.md
+
+-- Constraint on the version of Cabal needed to build this package.
+cabal-version:      >=1.10
+
+
+library
+  -- Modules exported by the library.
+  exposed-modules:  Data.Aeson.Parser.Parsec.Picky
+
+  -- Modules included in this library but not exported.
+  -- other-modules:
+
+  -- LANGUAGE extensions used by modules in this package.
+  -- other-extensions:
+
+  -- Other library packages from which modules are imported.
+  build-depends:      base >=4.7 && <5.0
+                    , aeson >= 0.10
+                    , parsec >= 3.0
+                    , scientific
+                    , text
+                    , unordered-containers
+                    , vector
+
+  -- Directories containing source files.
+  hs-source-dirs:   src
+
+  ghc-options:      -Wall
+
+  -- Base language which the package is written in.
+  default-language: Haskell2010
+
+source-repository head
+  type:             git
+  location:         https://github.com/FPBrno/aeson-parsec-picky
+
+source-repository this
+  type:             git
+  location:         https://github.com/FPBrno/aeson-parsec-picky
+  tag:              v0.1.0.0
diff --git a/src/Data/Aeson/Parser/Parsec/Picky.hs b/src/Data/Aeson/Parser/Parsec/Picky.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Aeson/Parser/Parsec/Picky.hs
@@ -0,0 +1,183 @@
+{-# LANGUAGE NoImplicitPrelude #-}
+-- |
+-- Module:       $HEADER$
+-- Description:  Picky JSON parser based on Parsec and Aeson
+-- Copyright:    (c) 2015, Matej Kollar
+-- License:      BSD3
+--
+-- Maintainer:   208115@mail.muni.cz
+--
+-- JSON parser with nice error messages and
+-- little more strict syntax (whitespace-wise).
+--
+-- In most cases you would want to use either 'value' or 'object'
+-- parser.
+module Data.Aeson.Parser.Parsec.Picky
+    (
+    -- * Parsers
+      string
+    , object
+    , array
+    , number
+    , bool
+    , null
+    , value
+    -- * Convenience functions
+    , eitherDecode
+    ) where
+
+import Prelude (Enum(toEnum), Int)
+
+import Control.Arrow (left)
+import Control.Applicative (pure, (<$>), (<|>), (<*), (<*>), (*>))
+import Control.Monad (Monad((>>=)), return, sequence, void)
+import Data.Bool (Bool(False, True), (&&))
+import Data.Either (Either(Left))
+import Data.Eq (Eq((/=)))
+import Data.Function (flip, ($), (.))
+import Data.List (concat)
+import Data.String (String)
+import Text.Read (read)
+import Text.Show (show)
+
+import qualified Data.HashMap.Strict as HashMap (fromList)
+import Data.Text (Text)
+import qualified Data.Text as Text (pack)
+import qualified Data.Vector as Vector (fromList)
+import Data.Scientific (Scientific)
+
+
+import Data.Aeson
+    ( FromJSON
+    , Result(Error, Success)
+    , fromJSON
+    )
+import Data.Aeson.Types
+    ( Value
+        ( Object
+        , Array
+        , String
+        , Number
+        , Bool
+        , Null
+        )
+    )
+import Text.Parsec
+    ( SourceName
+    , between
+    , char
+    , count
+    , digit
+    , eof
+    , hexDigit
+    , many
+    , many1
+    , newline
+    , option
+    , optional
+    , parse
+    , satisfy
+    , sepBy
+    , try
+    , (<?>)
+    )
+import qualified Text.Parsec as P (string)
+import Text.Parsec.Text (Parser)
+
+-- {{{ Helpers ----------------------------------------------------------------
+newlines :: Parser ()
+newlines = void $ many newline
+
+spaces :: Parser ()
+spaces = void $ many (char ' ')
+
+commaSeparated :: Parser a -> Parser [a]
+commaSeparated = flip sepBy comma where
+    comma = (variant1 <|> try variant2) <* spaces
+    variant1 = char ',' <* newlines
+    variant2 = pickySpaces *> char ','
+
+pickySpaces :: Parser ()
+pickySpaces = newlines *> spaces
+
+pickyBetween :: Parser a -> Parser b -> Parser c -> Parser c
+pickyBetween o c = between (o <* pickySpaces) (pickySpaces *> c)
+-- }}} Helpers ----------------------------------------------------------------
+
+-- {{{ Underlaying ------------------------------------------------------------
+baseString :: Parser Text
+baseString = Text.pack <$> p where
+    p = between (char '"') (char '"') $ many oneChar
+    oneChar = raw <|> char '\\' *> quoted
+    raw = satisfy (\ c -> c /= '"' && c /= '\\')
+    quoted = tab <|> quot <|> revsolidus <|> solidus <|> backspace <|> formfeed
+        <|> nl <|> cr <|> hexUnicode
+    tab = char 't' *> pure '\t'
+    quot = char '"' *> pure '"'
+    revsolidus = char '/' *> pure '/'
+    solidus = char '\\' *> pure '\\'
+    backspace = char 'b' *> pure '\b'
+    formfeed = char 'f' *> pure '\f'
+    nl = char 'n' *> pure '\n'
+    cr = char 'r' *> pure '\r'
+    hexUnicode = char 'u' *> count 4 hexDigit >>= decodeUtf
+    decodeUtf x = pure $ toEnum (read ('0':'x':x) :: Int)
+
+baseNumber :: Parser Scientific
+baseNumber = read . concat <$> sequence
+    [ opt $ P.string "-"
+    , P.string "0" <|> many1 digit
+    , opt $ (:) <$> char ':' <*> many1 digit
+    , opt $ concat <$> sequence
+        [ P.string "e" <|> P.string "E"
+        , opt $ P.string "+" <|> P.string "-"
+        , many1 digit
+        ]
+    ]
+    where
+    opt = option ""
+-- }}} Underlaying ------------------------------------------------------------
+
+-- {{{ JSON Values ------------------------------------------------------------
+-- | Parse just JSON string and nothing more.
+string :: Parser Value
+string = String <$> baseString <?> "JSON string"
+
+-- | Parse just JSON object and nothing more.
+object :: Parser Value
+object = Object . HashMap.fromList <$> p <?> "JSON object" where
+    p = pickyBetween (char '{') (char '}') $ commaSeparated pair
+    pair = (,) <$> (baseString <?> "JSON object key (string)")
+        <*> (char ':' *> pickySpaces *> value)
+
+-- | Parse just JSON array and nothing more.
+array :: Parser Value
+array = Array . Vector.fromList <$> p <?> "JSON array" where
+    p = pickyBetween (char '[') (char ']') $ commaSeparated value
+
+-- | Parse just JSON number and nothing more.
+number :: Parser Value
+number = Number <$> baseNumber <?> "JSON number"
+
+-- | Parse just JSON bool and nothing more.
+bool :: Parser Value
+bool = Bool <$> (true <|> false) <?> "JSON bool (true|false)" where
+    true = P.string "true" *> pure True
+    false = P.string "false" *> pure False
+
+-- | Parse just JSON null and nothing more.
+null :: Parser Value
+null = P.string "null" *> pure Null
+
+-- | Parse any JSON value but nothing more.
+value :: Parser Value
+value = object <|> array <|> string <|> number <|> bool <|> null
+-- }}} JSON Values ------------------------------------------------------------
+
+-- | Convenience function to parse JSON.
+eitherDecode :: FromJSON a => SourceName -> Text -> Either String a
+eitherDecode s i = left show (parse jsonEof s i) >>= f where
+    jsonEof = value <* optional newline <* eof
+    f j = case fromJSON j of
+        Success v -> return v
+        Error e -> Left e
