diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,3 @@
+# Version 0.1
+
+* First release
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,30 @@
+Copyright (c) 2015, Renzo Carbonara
+
+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 Renzo Carbonara 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 @@
+`instant-aeson` allows you to generically derive JSON representations (from the
+`aeson` package) for your types using `instant-generics`, which in particular,
+supports deriving generic representations for GADTs.
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/instant-aeson.cabal b/instant-aeson.cabal
new file mode 100644
--- /dev/null
+++ b/instant-aeson.cabal
@@ -0,0 +1,38 @@
+name:                instant-aeson
+version:             0.1
+author:              Renzo Carbonara
+maintainer:          renzo@carbonara.com.ar
+copyright:           Renzo Carbonara 2015
+license:             BSD3
+license-file:        LICENSE.txt
+category:            Web
+build-type:          Simple
+extra-source-files:  README.md CHANGELOG.md
+cabal-version:       >=1.18
+synopsis:            Generic Aeson instances through instant-generics
+
+library
+  hs-source-dirs: src/lib
+  default-language: Haskell2010
+  exposed-modules:
+      Generics.Instant.Functions.Aeson
+  build-depends:
+      aeson >=0.8 && <0.10
+    , base >=4.8 && <4.9
+    , instant-generics >=0.4 && <0.5
+  ghcjs-options: -Wall -O3
+  ghc-options: -Wall -O2
+
+
+test-suite tests
+  default-language: Haskell2010
+  type: exitcode-stdio-1.0
+  hs-source-dirs: tests
+  main-is: Main.hs
+  build-depends:
+      base >= 4 && < 5
+    , aeson
+    , tasty >= 0.10
+    , tasty-quickcheck >= 0.8
+    , instant-aeson
+    , instant-generics
diff --git a/src/lib/Generics/Instant/Functions/Aeson.hs b/src/lib/Generics/Instant/Functions/Aeson.hs
new file mode 100644
--- /dev/null
+++ b/src/lib/Generics/Instant/Functions/Aeson.hs
@@ -0,0 +1,204 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE PolyKinds #-}
+
+module Generics.Instant.Functions.Aeson
+  ( -- $defaults
+    gtoJSON
+  , gparseJSON
+    -- * Internals
+  , GToJSON
+  , GFromJSON
+    -- ** Even more internal
+  , GSumFromJSON
+  , GSumToJSON
+  , GSumSize
+  ) where
+
+import qualified Data.Aeson as Ae
+import qualified Data.Aeson.Types as Ae
+import           Data.Bits
+import           Generics.Instant
+
+--------------------------------------------------------------------------------
+-- $defaults
+--
+-- You can use 'gtoJSON' and 'gparseJSON' as your generic 'Ae.toJSON' and
+-- 'Ae.parseJSON' implementations for any 'Representable' type as follows:
+--
+-- @
+-- instance 'Ae.ToJSON' MyType where toJSON = 'gtoJSON'
+-- instance 'Ae.FromJSON' MyType where parseJSON = 'gparseJSON'
+-- @
+
+gtoJSON :: (Representable a, GToJSON (Rep a)) => a -> Ae.Value
+gtoJSON = \a -> gtoJSON' (from a)
+{-# INLINABLE gtoJSON #-}
+
+gparseJSON :: (Representable a, GFromJSON (Rep a)) => Ae.Value -> Ae.Parser a
+gparseJSON = \v -> fmap to (gparseJSON' v)
+{-# INLINABLE gparseJSON #-}
+
+--------------------------------------------------------------------------------
+
+class GFromJSON a where
+  gparseJSON' :: Ae.Value -> Ae.Parser a
+
+instance GFromJSON Z where
+  gparseJSON' _ = fail
+    "Generics.Instant.Functions.Aeson.GFromJSON Z gparseJSON' - impossible"
+
+instance GFromJSON U where
+  gparseJSON' v = U <$ (Ae.parseJSON v :: Ae.Parser ())
+  {-# INLINABLE gparseJSON' #-}
+
+instance GFromJSON a => GFromJSON (CEq c p p a) where
+  gparseJSON' v = gparseJSON' v >>= \a -> return (C a)
+  {-# INLINABLE gparseJSON' #-}
+
+instance {-# OVERLAPPABLE #-} GFromJSON (CEq c p q a) where
+  gparseJSON' _ = fail
+    "Generics.Instant.Functions.Aeson.GFtomJSON (CEq c p q a) gparseJSON' - impossible"
+
+instance Ae.FromJSON a => GFromJSON (Var a) where
+  gparseJSON' v = Ae.parseJSON v >>= \a -> return (Var a)
+  {-# INLINABLE gparseJSON' #-}
+
+instance Ae.FromJSON a => GFromJSON (Rec a) where
+  gparseJSON' v = Ae.parseJSON v >>= \a -> return (Rec a)
+  {-# INLINABLE gparseJSON' #-}
+
+instance (GFromJSON a, GFromJSON b) => GFromJSON (a :*: b) where
+  gparseJSON' v = Ae.parseJSON v >>= \(va, vb) ->
+                  gparseJSON' va >>= \a ->
+                  gparseJSON' vb >>= \b ->
+                  return (a :*: b)
+  {-# INLINABLE gparseJSON' #-}
+
+-- Borrowed from the "binary" package, which borrowed this from "cereal".
+instance
+  ( GSumFromJSON a, GSumFromJSON b, GSumSize a, GSumSize b
+  , GFromJSON a, GFromJSON b
+  ) => GFromJSON (a :+: b)
+  where
+    gparseJSON' v = Ae.parseJSON v >>= \(code, v') ->
+      let size = unTagged (sumSize :: Tagged (a :+: b) Integer)
+      in if code < size
+         then gsumParseJSON code size v'
+         else fail "Generics.Instant.Functions.Aeson.GFromJSON (a :+: b) - \
+                   \Unknown constructor"
+    {-# INLINABLE gparseJSON' #-}
+
+--------------------------------------------------------------------------------
+
+class GToJSON a where
+  gtoJSON' :: a -> Ae.Value
+
+instance GToJSON Z where
+  gtoJSON' _ = error
+    "Generics.Instant.Functions.Aeson.GToJSON Z gtoJSON' - impossible"
+
+instance GToJSON U where
+  gtoJSON' U = Ae.toJSON ()
+  {-# INLINABLE gtoJSON' #-}
+
+instance GToJSON a => GToJSON (CEq c p p a) where
+  gtoJSON' (C a) = gtoJSON' a
+  {-# INLINABLE gtoJSON' #-}
+
+instance {-# OVERLAPPABLE #-} GToJSON a => GToJSON (CEq c p q a) where
+  gtoJSON' (C a) = gtoJSON' a
+  {-# INLINABLE gtoJSON' #-}
+
+instance Ae.ToJSON a => GToJSON (Var a) where
+  gtoJSON' (Var a) = Ae.toJSON a
+  {-# INLINABLE gtoJSON' #-}
+
+instance Ae.ToJSON a => GToJSON (Rec a) where
+  gtoJSON' (Rec a) = Ae.toJSON a
+  {-# INLINABLE gtoJSON' #-}
+
+instance (GToJSON a, GToJSON b) => GToJSON (a :*: b) where
+  gtoJSON' (a :*: b) = Ae.toJSON (gtoJSON' a, gtoJSON' b)
+  {-# INLINABLE gtoJSON' #-}
+
+-- Borrowed from the "binary" package, which borrowed this from "cereal".
+instance
+  ( GSumToJSON a, GSumToJSON b, GSumSize a, GSumSize b
+  , GToJSON a, GToJSON b
+  ) => GToJSON (a :+: b)
+  where
+    gtoJSON' x =
+      let size = unTagged (sumSize :: Tagged (a :+: b) Integer)
+      in gsumToJSON 0 size x
+    {-# INLINABLE gtoJSON' #-}
+
+--------------------------------------------------------------------------------
+
+class GSumFromJSON a where
+  gsumParseJSON :: Integer -> Integer -> Ae.Value -> Ae.Parser a
+
+instance
+  ( GSumFromJSON a, GSumFromJSON b, GFromJSON a, GFromJSON b
+  ) => GSumFromJSON (a :+: b)
+  where
+    {-# INLINABLE gsumParseJSON #-}
+    gsumParseJSON !code !size v
+      | code < sizeL = L <$> gsumParseJSON code           sizeL v
+      | otherwise    = R <$> gsumParseJSON (code - sizeL) sizeR v
+      where
+        sizeL = size `shiftR` 1
+        sizeR = size - sizeL
+
+instance GFromJSON a => GSumFromJSON (CEq c p p a) where
+  gsumParseJSON _ _ v = gparseJSON' v
+  {-# INLINABLE gsumParseJSON #-}
+
+instance {-# OVERLAPPABLE #-} GSumFromJSON (CEq c p q a) where
+  gsumParseJSON _ _ _ = fail
+    "Generics.Instant.Functions.Aeson.GSumFromJSON (CEq c p q a) - impossible"
+
+--------------------------------------------------------------------------------
+
+class GSumToJSON a where
+  gsumToJSON :: Integer -> Integer -> a -> Ae.Value
+
+instance
+  ( GSumToJSON a, GSumToJSON b, GToJSON a, GToJSON b
+  ) => GSumToJSON (a :+: b)
+  where
+    {-# INLINABLE gsumToJSON #-}
+    gsumToJSON !code !size x =
+      let sizeL = size `shiftR` 1
+          sizeR = size - sizeL
+      in case x of
+           L l -> gsumToJSON code           sizeL l
+           R r -> gsumToJSON (code + sizeL) sizeR r
+
+instance GToJSON a => GSumToJSON (CEq c p p a) where
+  gsumToJSON !code _ ca = Ae.toJSON (code, gtoJSON' ca)
+  {-# INLINABLE gsumToJSON #-}
+
+instance {-# OVERLAPPABLE #-} GToJSON a => GSumToJSON (CEq c p q a) where
+  gsumToJSON !code _ ca = Ae.toJSON (code, gtoJSON' ca)
+  {-# INLINABLE gsumToJSON #-}
+
+--------------------------------------------------------------------------------
+
+class GSumSize a where
+  sumSize :: Tagged a Integer
+
+newtype Tagged s b = Tagged { unTagged :: b }
+
+instance (GSumSize a, GSumSize b) => GSumSize (a :+: b) where
+  {-# INLINABLE sumSize #-}
+  sumSize = Tagged (unTagged (sumSize :: Tagged a Integer) +
+                    unTagged (sumSize :: Tagged b Integer))
+
+instance GSumSize (CEq c p q a) where
+  {-# INLINABLE sumSize #-}
+  sumSize = Tagged 1
diff --git a/tests/Main.hs b/tests/Main.hs
new file mode 100644
--- /dev/null
+++ b/tests/Main.hs
@@ -0,0 +1,143 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Main where
+
+import Test.Tasty
+import Test.Tasty.QuickCheck as QC
+
+import qualified Data.Aeson
+import qualified Data.Aeson as Ae
+import qualified Data.Aeson.Types as Ae
+import Data.Proxy
+
+import qualified Generics.Instant as GI
+import qualified Generics.Instant.TH as GI
+import Generics.Instant.Functions.Aeson (GFromJSON, gparseJSON, GToJSON, gtoJSON)
+
+--------------------------------------------------------------------------------
+-- orphans
+
+data Unit_Unit_
+instance GI.Constructor Unit_Unit_ where conName _ = "()"
+instance GI.Representable () where
+  type Rep () = GI.U
+  from () = GI.U
+  to GI.U = ()
+
+GI.deriveAll ''Either
+
+instance Arbitrary (Proxy a) where arbitrary = return Proxy
+instance Ae.ToJSON (Proxy a) where toJSON _ = Ae.toJSON ()
+instance Ae.FromJSON (Proxy a) where parseJSON v = Ae.parseJSON v >>= \() -> return Proxy
+
+--------------------------------------------------------------------------------
+-- many constructors, recursive
+
+data ZZ = ZZ1 Int | ZZ2 Char | ZZ3 ZZ deriving (Show, Eq)
+GI.deriveAll ''ZZ
+instance Arbitrary ZZ where
+  arbitrary = QC.oneof [ ZZ1 <$> QC.arbitrary
+                       , ZZ2 <$> QC.arbitrary
+                       , ZZ3 <$> QC.arbitrary ]
+
+instance Ae.ToJSON ZZ where toJSON = gtoJSON
+instance Ae.FromJSON ZZ where parseJSON = gparseJSON
+
+--------------------------------------------------------------------------------
+-- GADT
+
+data Foo1 (a :: *) :: * where
+  Foo1_1 :: Bool -> Foo1 Bool
+  Foo1_2 :: a -> Foo1 a
+GI.deriveAll ''Foo1
+deriving instance Eq a => Eq (Foo1 a)
+deriving instance Show a => Show (Foo1 a)
+instance QC.Arbitrary (Foo1 Bool) where
+  arbitrary = Foo1_1 <$> QC.arbitrary
+instance {-# OVERLAPPABLE #-} (QC.Arbitrary a, GI.Representable a) => QC.Arbitrary (Foo1 a) where
+  arbitrary = Foo1_2 <$> QC.arbitrary
+
+
+data Foo2 (a :: *) (b :: *) :: * where
+  Foo2_1 :: a -> Char -> Foo2 a Int
+  Foo2_2 :: a -> b -> Foo2 a b
+GI.deriveAll ''Foo2
+deriving instance (Eq a, Eq b) => Eq (Foo2 a b)
+deriving instance (Show a, Show b) => Show (Foo2 a b)
+instance (QC.Arbitrary a, GI.Representable a) => QC.Arbitrary (Foo2 a Int) where
+  arbitrary = Foo2_1 <$> QC.arbitrary <*> QC.arbitrary
+instance {-# OVERLAPPABLE #-} (QC.Arbitrary a, GI.Representable a, QC.Arbitrary b, GI.Representable b) => QC.Arbitrary (Foo2 a b) where
+  arbitrary = Foo2_2 <$> QC.arbitrary <*> QC.arbitrary
+
+
+data Bar1 (a :: Bool) :: * where
+  Bar1_1 :: Char -> Bar1 'True
+  Bar1_2 :: Int -> Bar1 'False
+GI.deriveAll ''Bar1
+deriving instance Eq (Bar1 a)
+deriving instance Show (Bar1 a)
+instance QC.Arbitrary (Bar1 'True) where
+  arbitrary = Bar1_1 <$> QC.arbitrary
+instance QC.Arbitrary (Bar1 'False) where
+  arbitrary = Bar1_2 <$> QC.arbitrary
+
+data Bar2 (a :: k1) (b :: Bool) :: * where
+  Bar2_1 :: Int -> Proxy a -> Bar2 a 'True
+  Bar2_2 :: String -> Proxy a -> Bar2 a 'False
+GI.deriveAll ''Bar2
+deriving instance Eq (Bar2 a b)
+deriving instance Show (Bar2 a b)
+instance (QC.Arbitrary a) => QC.Arbitrary (Bar2 a 'True) where
+  arbitrary = Bar2_1 <$> QC.arbitrary <*> QC.arbitrary
+instance (QC.Arbitrary a) => QC.Arbitrary (Bar2 a 'False) where
+  arbitrary = Bar2_2 <$> QC.arbitrary <*> QC.arbitrary
+
+
+--------------------------------------------------------------------------------
+
+main :: IO ()
+main = defaultMain tests
+
+tests :: TestTree
+tests = testGroup "QuickCheck - prop_IdJSON"
+  [ -- QC.testProperty "()" (prop_IdJSON :: () -> Bool)
+--   , QC.testProperty "Bool" (prop_IdJSON :: Bool -> Bool)
+--   , QC.testProperty "Char" (prop_IdJSON :: Char -> Bool)
+--   , QC.testProperty "Float" (prop_IdJSON :: Float -> Bool)
+--   , QC.testProperty "Int" (prop_IdJSON :: Int -> Bool)
+    QC.testProperty "Maybe ()" (prop_IdJSON :: Maybe () -> Bool)
+  , QC.testProperty "Maybe Bool" (prop_IdJSON :: Maybe Bool -> Bool)
+  , QC.testProperty "Maybe Char" (prop_IdJSON :: Maybe Char -> Bool)
+  , QC.testProperty "Maybe Float" (prop_IdJSON :: Maybe Float -> Bool)
+  , QC.testProperty "Maybe Int" (prop_IdJSON :: Maybe Int -> Bool)
+  , QC.testProperty "Maybe ZZ" (prop_IdJSON :: Maybe ZZ -> Bool)
+  , QC.testProperty "[()]" (prop_IdJSON :: [()] -> Bool)
+  , QC.testProperty "[Bool]" (prop_IdJSON :: [Bool] -> Bool)
+  , QC.testProperty "[Char]" (prop_IdJSON :: [Char] -> Bool)
+  , QC.testProperty "[Float]" (prop_IdJSON :: [Float] -> Bool)
+  , QC.testProperty "[Int]" (prop_IdJSON :: [Int] -> Bool)
+  , QC.testProperty "[ZZ]" (prop_IdJSON :: [ZZ] -> Bool)
+  , QC.testProperty "Foo1 Int" (prop_IdJSON :: Foo1 Int -> Bool)
+  , QC.testProperty "Foo1 Char" (prop_IdJSON :: Foo1 Char -> Bool)
+  , QC.testProperty "Foo2 Float Int" (prop_IdJSON :: Foo2 Float Int -> Bool)
+  , QC.testProperty "Foo2 Bool Char" (prop_IdJSON :: Foo2 Bool Char -> Bool)
+  , QC.testProperty "Bar1 'True" (prop_IdJSON :: Bar1 'True -> Bool)
+  , QC.testProperty "Bar1 'False" (prop_IdJSON :: Bar1 'False -> Bool)
+  , QC.testProperty "Bar2 Int 'True" (prop_IdJSON :: Bar2 Int 'True -> Bool)
+  , QC.testProperty "Bar2 Float 'False" (prop_IdJSON :: Bar2 Float 'False -> Bool)
+  ]
+
+prop_IdJSON
+  :: (Eq a, GI.Representable a, GToJSON (GI.Rep a), GFromJSON (GI.Rep a), Show a)
+  => a -> Bool
+prop_IdJSON a = maybe False (== a) $ Ae.parseMaybe gparseJSON (gtoJSON a)
