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,4 @@
+`instant-bytes` allows you to generically derive binary representations
+(from the `bytes` 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-bytes.cabal b/instant-bytes.cabal
new file mode 100644
--- /dev/null
+++ b/instant-bytes.cabal
@@ -0,0 +1,38 @@
+name:                instant-bytes
+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 Serial instances through instant-generics
+
+library
+  hs-source-dirs: src/lib
+  default-language: Haskell2010
+  exposed-modules:
+      Generics.Instant.Functions.Bytes
+  build-depends:
+      bytes >=0.15 && <0.16
+    , 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
+    , bytes
+    , tasty >= 0.10
+    , tasty-quickcheck >= 0.8
+    , instant-bytes
+    , instant-generics
diff --git a/src/lib/Generics/Instant/Functions/Bytes.hs b/src/lib/Generics/Instant/Functions/Bytes.hs
new file mode 100644
--- /dev/null
+++ b/src/lib/Generics/Instant/Functions/Bytes.hs
@@ -0,0 +1,204 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+
+module Generics.Instant.Functions.Bytes
+  ( -- $defaults
+    gserialize
+  , gdeserialize
+    -- * Internals
+  , GSerial
+    -- ** Even more internal
+  , GSumSerial
+  , GSumSize
+  ) where
+
+import qualified Data.Bytes.Serial as Bytes
+import qualified Data.Bytes.Put as Bytes
+import qualified Data.Bytes.Get as Bytes
+import Data.Bits
+import Data.Word
+import Generics.Instant
+import Prelude
+
+--------------------------------------------------------------------------------
+-- $defaults
+--
+-- You can use 'gserialize' and 'gdeserialize' as your generic 'Bytes.serialize'
+-- and 'Bytes.deserialize' implementations for any 'Representable' type as
+-- follows:
+--
+-- @
+-- instance 'Bytes.Serial' MyType where
+--    serialize = 'gserialize'
+--    deserialize = 'gdeserialize'
+-- @
+
+gserialize :: (Representable a, GSerial (Rep a), Bytes.MonadPut m) => a -> m ()
+gserialize = \a -> gserialize' (from a)
+{-# INLINABLE gserialize #-}
+
+gdeserialize :: (Representable a, GSerial (Rep a), Bytes.MonadGet m) => m a
+gdeserialize = fmap to gdeserialize'
+{-# INLINABLE gdeserialize #-}
+
+--------------------------------------------------------------------------------
+
+class GSerial a where
+  gserialize' :: Bytes.MonadPut m => a -> m ()
+  gdeserialize' :: Bytes.MonadGet m => m a
+
+instance GSerial Z where
+  gserialize' _ = fail "Generics.Instant.Functions.Serial.GSerial Z gserialize' - impossible"
+  gdeserialize' = fail "Generics.Instant.Functions.Serial.GSerial Z gdeserialize' - impossible"
+
+instance GSerial U where
+  gserialize' U = Bytes.serialize ()
+  {-# INLINABLE gserialize' #-}
+  gdeserialize' = Bytes.deserialize >>= \() -> return U
+  {-# INLINABLE gdeserialize' #-}
+
+instance GSerial a => GSerial (CEq c p p a) where
+  gserialize' (C a) = gserialize' a
+  {-# INLINABLE gserialize' #-}
+  gdeserialize' = gdeserialize' >>= \a -> return (C a)
+  {-# INLINABLE gdeserialize' #-}
+
+instance {-# OVERLAPPABLE #-} GSerial a => GSerial (CEq c p q a) where
+  gserialize' (C a) = gserialize' a
+  {-# INLINABLE gserialize' #-}
+  gdeserialize' = fail "Generics.Instant.Functions.Serial.GSerial (CEq c p q a) gdeserialize' - impossible"
+
+instance Bytes.Serial a => GSerial (Var a) where
+  gserialize' (Var a) = Bytes.serialize a
+  {-# INLINABLE gserialize' #-}
+  gdeserialize' = Bytes.deserialize >>= \a -> return (Var a)
+  {-# INLINABLE gdeserialize' #-}
+
+instance Bytes.Serial a => GSerial (Rec a) where
+  gserialize' (Rec a) = Bytes.serialize a
+  {-# INLINABLE gserialize' #-}
+  gdeserialize' = Bytes.deserialize >>= \a -> return (Rec a)
+  {-# INLINABLE gdeserialize' #-}
+
+instance (GSerial a, GSerial b) => GSerial (a :*: b) where
+  gserialize' (a :*: b) = gserialize' a >> gserialize' b
+  {-# INLINABLE gserialize' #-}
+  gdeserialize' = gdeserialize' >>= \a ->
+                  gdeserialize' >>= \b ->
+                  return (a :*: b)
+  {-# INLINABLE gdeserialize' #-}
+
+---
+
+-- Borrowed from the "binary" package, which borrowed this from "cereal".
+
+-- The following GSerial instance for sums has support for serializing
+-- types with up to 2^64-1 constructors. It will use the minimal
+-- number of bytes needed to encode the constructor. For example when
+-- a type has 2^8 constructors or less it will use a single byte to
+-- encode the constructor. If it has 2^16 constructors or less it will
+-- use two bytes, and so on till 2^64-1.
+
+instance
+  ( GSumSerial a, GSumSerial b, GSerial a, GSerial b, GSumSize a, GSumSize b
+  ) => GSerial (a :+: b)
+  where
+    {-# INLINABLE gserialize' #-}
+    gserialize' x
+      | predSize <= fromIntegral (maxBound :: Word8)
+          = putSum (0 :: Word8) (fromIntegral size) x
+      | predSize <= fromIntegral (maxBound :: Word16)
+          = putSum (0 :: Word16) (fromIntegral size) x
+      | predSize <= fromIntegral (maxBound :: Word32)
+          = putSum (0 :: Word32) (fromIntegral size) x
+      | predSize <= fromIntegral (maxBound :: Word64)
+          = putSum (0 :: Word64) (fromIntegral size) x
+      | otherwise = sizeError "encode" size
+      where
+        size = unTagged (sumSize :: Tagged (a :+: b) Word64)
+        predSize = size - 1
+
+    {-# INLINABLE gdeserialize' #-}
+    gdeserialize'
+      | predSize <= fromIntegral (maxBound :: Word8)
+          = Bytes.deserialize >>= \(c :: Word8) ->
+            checkGetSum (fromIntegral size) c
+      | predSize <= fromIntegral (maxBound :: Word16)
+          = Bytes.deserialize >>= \(c :: Word16) ->
+            checkGetSum (fromIntegral size) c
+      | predSize <= fromIntegral (maxBound :: Word32)
+          = Bytes.deserialize >>= \(c :: Word32) ->
+            checkGetSum (fromIntegral size) c
+      | predSize <= fromIntegral (maxBound :: Word64)
+          = Bytes.deserialize >>= \(c :: Word64) ->
+            checkGetSum (fromIntegral size) c
+      | otherwise = sizeError "decode" size
+      where
+        size = unTagged (sumSize :: Tagged (a :+: b) Word64)
+        predSize = size - 1
+
+sizeError :: Show size => String -> size -> error
+sizeError s size =
+  error $ "Generics.Instant.Functions.Serial.sizeError: Can't " ++ s ++ " a type with " ++
+          show size ++ " constructors"
+
+------------------------------------------------------------------------
+
+checkGetSum
+  :: (Ord w, Num w, Bits w, GSumSerial a, Bytes.MonadGet m) => w -> w -> m a
+checkGetSum size code
+  | code < size = getSum code size
+  | otherwise = fail "Generics.Instant.Functions.Serial.checkGetSum: Unknown encoding for constructor"
+{-# INLINABLE checkGetSum #-}
+
+class GSumSerial a where
+  putSum :: (Num w, Bits w, Bytes.Serial w, Bytes.MonadPut m) => w -> w -> a -> m ()
+  getSum :: (Ord w, Num w, Bits w, Bytes.MonadGet m) => w -> w -> m a
+
+instance (GSumSerial a, GSumSerial b, GSerial a, GSerial b) => GSumSerial (a :+: b) where
+  {-# INLINABLE putSum #-}
+  putSum !code !size x =
+    let sizeL = size `shiftR` 1
+        sizeR = size - sizeL
+    in case x of
+         L l -> putSum code           sizeL l
+         R r -> putSum (code + sizeL) sizeR r
+  {-# INLINABLE getSum #-}
+  getSum !code !size
+    | code < sizeL = L <$> getSum code           sizeL
+    | otherwise    = R <$> getSum (code - sizeL) sizeR
+    where
+      sizeL = size `shiftR` 1
+      sizeR = size - sizeL
+
+instance GSerial a => GSumSerial (CEq c p p a) where
+  putSum !code _ ca = Bytes.serialize code >> gserialize' ca
+  {-# INLINABLE putSum #-}
+  getSum _ _ = gdeserialize'
+  {-# INLINABLE getSum #-}
+
+instance {-# OVERLAPPABLE #-} GSerial a => GSumSerial (CEq c p q a) where
+  putSum !code _ ca = Bytes.serialize code >> gserialize' ca
+  {-# INLINABLE putSum #-}
+  getSum _ _ = fail "Generics.Instant.Functions.Serial.GSumSerial (CEq c p q a) getSum - impossible"
+
+------------------------------------------------------------------------
+
+class GSumSize a where
+  sumSize :: Tagged a Word64
+
+newtype Tagged s b = Tagged {unTagged :: b}
+
+instance (GSumSize a, GSumSize b) => GSumSize (a :+: b) where
+  {-# INLINABLE sumSize #-}
+  sumSize = Tagged (unTagged (sumSize :: Tagged a Word64) +
+                    unTagged (sumSize :: Tagged b Word64))
+
+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,144 @@
+{-# 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.Bytes.Serial as Bytes
+import qualified Data.Bytes.Put as Bytes
+import qualified Data.Bytes.Get as Bytes
+import Data.Proxy
+
+import qualified Generics.Instant as GI
+import qualified Generics.Instant.TH as GI
+import Generics.Instant.Functions.Bytes (GSerial, gserialize, gdeserialize)
+
+--------------------------------------------------------------------------------
+-- 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 = ()
+
+instance Arbitrary (Proxy a) where
+  arbitrary = return Proxy
+instance Bytes.Serial (Proxy a) where
+  serialize _ = Bytes.serialize ()
+  deserialize = Bytes.deserialize >>= \() -> return Proxy
+
+--------------------------------------------------------------------------------
+-- many constructors, recursive
+
+data ZZ = ZZ1 Int | ZZ2 Char | ZZ3 ZZ deriving (Show, Eq)
+GI.deriveAll ''ZZ
+instance Bytes.Serial ZZ where
+  serialize = gserialize
+  deserialize = gdeserialize
+instance Arbitrary ZZ where
+  arbitrary = QC.oneof [ ZZ1 <$> QC.arbitrary
+                       , ZZ2 <$> QC.arbitrary
+                       , ZZ3 <$> QC.arbitrary ]
+
+--------------------------------------------------------------------------------
+-- 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_IdGSerial"
+  [ -- QC.testProperty "()" (prop_IdGSerial :: () -> Bool)
+--   , QC.testProperty "Bool" (prop_IdGSerial :: Bool -> Bool)
+--   , QC.testProperty "Char" (prop_IdGSerial :: Char -> Bool)
+--   , QC.testProperty "Float" (prop_IdGSerial :: Float -> Bool)
+--   , QC.testProperty "Int" (prop_IdGSerial :: Int -> Bool)
+    QC.testProperty "Maybe ()" (prop_IdGSerial :: Maybe () -> Bool)
+  , QC.testProperty "Maybe Bool" (prop_IdGSerial :: Maybe Bool -> Bool)
+  , QC.testProperty "Maybe Char" (prop_IdGSerial :: Maybe Char -> Bool)
+  , QC.testProperty "Maybe Float" (prop_IdGSerial :: Maybe Float -> Bool)
+  , QC.testProperty "Maybe Int" (prop_IdGSerial :: Maybe Int -> Bool)
+  , QC.testProperty "Maybe ZZ" (prop_IdGSerial :: Maybe ZZ -> Bool)
+  , QC.testProperty "[()]" (prop_IdGSerial :: [()] -> Bool)
+  , QC.testProperty "[Bool]" (prop_IdGSerial :: [Bool] -> Bool)
+  , QC.testProperty "[Char]" (prop_IdGSerial :: [Char] -> Bool)
+  , QC.testProperty "[Float]" (prop_IdGSerial :: [Float] -> Bool)
+  , QC.testProperty "[Int]" (prop_IdGSerial :: [Int] -> Bool)
+  , QC.testProperty "[ZZ]" (prop_IdGSerial :: [ZZ] -> Bool)
+  , QC.testProperty "Foo1 Int" (prop_IdGSerial :: Foo1 Int -> Bool)
+  , QC.testProperty "Foo1 Char" (prop_IdGSerial :: Foo1 Char -> Bool)
+  , QC.testProperty "Foo2 Float Int" (prop_IdGSerial :: Foo2 Float Int -> Bool)
+  , QC.testProperty "Foo2 Bool Char" (prop_IdGSerial :: Foo2 Bool Char -> Bool)
+  , QC.testProperty "Bar1 'True" (prop_IdGSerial :: Bar1 'True -> Bool)
+  , QC.testProperty "Bar1 'False" (prop_IdGSerial :: Bar1 'False -> Bool)
+  , QC.testProperty "Bar2 Int 'True" (prop_IdGSerial :: Bar2 Int 'True -> Bool)
+  , QC.testProperty "Bar2 Float 'False" (prop_IdGSerial :: Bar2 Float 'False -> Bool)
+  ]
+
+prop_IdGSerial
+  :: (Eq a, GI.Representable a, GSerial (GI.Rep a), Show a)
+  => a -> Bool
+prop_IdGSerial a =
+  a == Bytes.runGetL gdeserialize (Bytes.runPutL (gserialize a))
