diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2013, 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/NEWS b/NEWS
new file mode 100644
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,3 @@
+# Version 0.1.0.0
+
+* Initial version.
diff --git a/PEOPLE b/PEOPLE
new file mode 100644
--- /dev/null
+++ b/PEOPLE
@@ -0,0 +1,5 @@
+The following people have participated in creating this library, either
+by directly contributing code or by providing thoughtful input in
+discussions about the library design.
+
+Renzo Carbonara
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+# pipes-binary
+
+Utilities to encode and decode binary streams using the **pipes** and
+**binary** libraries.
+
+Check the source or rendered Haddocks for extensive documentation.
+
+This code is licensed under the terms of the so called **3-clause BSD
+license**. Read the file named ``LICENSE`` found in this same directory
+for details.
+
+See the ``PEOPLE`` file to learn about the people involved in this
+effort.
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/pipes-binary.cabal b/pipes-binary.cabal
new file mode 100644
--- /dev/null
+++ b/pipes-binary.cabal
@@ -0,0 +1,36 @@
+name:               pipes-binary
+version:            0.1.0.0
+license:            BSD3
+license-file:       LICENSE
+copyright:          Copyright (c) Renzo Carbonara 2013
+author:             Renzo Carbonara
+maintainer:         renzocarbonaraλgmail.com
+stability:          Experimental
+tested-with:        GHC == 7.4.1
+homepage:           https://github.com/k0001/pipes-binary
+bug-reports:        https://github.com/k0001/pipes-binary/issues
+category:           Pipes
+build-type:         Simple
+synopsis:           Encode and decode binary streams using the pipes and binary libraries.
+cabal-version:      >=1.8
+extra-source-files: README.md PEOPLE NEWS
+description:
+  Encode and decode binary streams using the @Pipes@ and @binary@ libraries.
+  .
+  See the @NEWS@ file in the source distribution to learn about any
+  important changes between version.
+
+source-repository head
+    type: git
+    location: git://github.com/k0001/pipes-binary.git
+
+library
+    hs-source-dirs:    src
+    build-depends:     base           (==4.*)
+                     , binary         (>=0.7 && <0.8)
+                     , bytestring     (>=0.9.2.1)
+                     , pipes          (>=3.3 && <3.4)
+                     , pipes-parse    (>=1.0 && <1.1)
+    exposed-modules:   Control.Proxy.Binary
+    other-modules:     Control.Proxy.Binary.Internal
+    ghc-options: -Wall -O2
diff --git a/src/Control/Proxy/Binary.hs b/src/Control/Proxy/Binary.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Proxy/Binary.hs
@@ -0,0 +1,122 @@
+-- | This module exports facilities that allows you to encode and decode
+-- streams of 'Bin.Binary' values using the @pipes@ and @pipes-parse@ libraries.
+
+module Control.Proxy.Binary
+  ( -- * Decoding
+    -- $decoding
+    decode
+  , decodeD
+    -- * Encoding
+    -- $encoding
+  , encode
+  , encodeD
+   -- * Types
+  , I.DecodingError(..)
+  ) where
+
+-------------------------------------------------------------------------------
+
+import qualified Data.ByteString               as BS
+import qualified Data.ByteString.Lazy.Internal as BLI
+import           Control.Monad                 (unless)
+import qualified Control.Proxy                 as P
+import qualified Control.Proxy.Binary.Internal as I
+import qualified Control.Proxy.Parse           as Pa
+import qualified Control.Proxy.Trans.Either    as P
+import qualified Control.Proxy.Trans.State     as P
+import qualified Data.Binary                   as Bin
+import           Data.Foldable                 (mapM_)
+import           Data.Function                 (fix)
+import           Prelude                       hiding (mapM_)
+
+--------------------------------------------------------------------------------
+-- $decoding
+--
+-- There are two different 'Bin.Binary' decoding facilities exported by this
+-- module, and choosing between them is easy: If you need to interleave decoding
+-- with other stream effects you must use 'decode', otherwise you may use the
+-- simpler 'decodeD'.
+
+-- | Decodes one 'Bin.Binary' instance flowing downstream.
+--
+-- * In case of decoding errors, a 'I.DecodingError' exception is thrown in the
+-- 'Pe.EitherP' proxy transformer.
+--
+-- * Requests more input from upstream using 'Pa.draw' when needed.
+--
+-- * /Do not/ use this proxy if 'Control.Proxy.ByteString.isEndOfBytes' returns
+-- 'True', otherwise you may get unexpected decoding errors.
+decode
+  :: (P.Proxy p, Monad m, Bin.Binary r)
+  => P.EitherP I.DecodingError (P.StateP [BS.ByteString] p)
+     () (Maybe BS.ByteString) y' y m r
+decode = do
+    (er, mlo) <- P.liftP (I.parseWith Pa.draw Bin.get)
+    P.liftP (mapM_ Pa.unDraw mlo)
+    either P.throw return er
+{-# INLINABLE decode #-}
+
+
+-- | Decodes 'Bin.Binary' instances flowing downstream until end of input.
+--
+-- * In case of decoding errors, a 'I.DecodingError' exception is thrown in the
+-- 'Pe.EitherP' proxy transformer.
+--
+-- * Requests more input from upstream using 'Pa.draw', when needed.
+--
+-- * Empty input chunks flowing downstream will be discarded.
+decodeD
+  :: (P.Proxy p, Monad m, Bin.Binary b)
+  => ()
+  -> P.Pipe (P.EitherP I.DecodingError (P.StateP [BS.ByteString] p))
+     (Maybe BS.ByteString) b m ()
+decodeD = \() -> loop where
+    loop = do
+        eof <- P.liftP isEndOfBytes
+        unless eof $ decode >>= P.respond >> loop
+{-# INLINABLE decodeD #-}
+
+--------------------------------------------------------------------------------
+-- $encoding
+--
+-- There are two different 'Bin.Binary' encoding facilities exported by this
+-- module, and choosing between them is easy: If you need to interleave encoding
+-- with other stream effects you must use 'encode', otherwise you may use the
+-- simpler 'encodeD'.
+
+-- | Encodes the given 'Bin.Binary' instance and sends it downstream in
+-- 'BS.ByteString' chunks.
+encode
+  :: (P.Proxy p, Monad m, Bin.Binary x)
+  => x -> p x' x () BS.ByteString m ()
+encode = \x -> P.runIdentityP $ do
+    BLI.foldrChunks (\e a -> P.respond e >> a) (return ()) (Bin.encode x)
+{-# INLINABLE encode #-}
+
+
+-- | Encodes 'Bin.Binary' instances flowing downstream, each in possibly more
+-- than one 'BS.ByteString' chunk.
+encodeD
+  :: (P.Proxy p, Monad m, Bin.Binary a)
+  => () -> P.Pipe p a BS.ByteString m r
+encodeD = P.pull P./>/ encode
+{-# INLINABLE encodeD #-}
+
+
+--------------------------------------------------------------------------------
+-- XXX: this function is here until pipes-bytestring exports it
+
+-- | Like 'Pa.isEndOfInput', except it also consumes and discards leading
+-- empty 'BS.ByteString' chunks.
+isEndOfBytes
+  :: (Monad m, P.Proxy p)
+  => P.StateP [BS.ByteString] p () (Maybe BS.ByteString) y' y m Bool
+isEndOfBytes = fix $ \loop -> do
+    ma <- Pa.draw
+    case ma of
+      Just a
+       | BS.null a -> loop
+       | otherwise -> Pa.unDraw a >> return False
+      Nothing      -> return True
+{-# INLINABLE isEndOfBytes #-}
+
diff --git a/src/Control/Proxy/Binary/Internal.hs b/src/Control/Proxy/Binary/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Proxy/Binary/Internal.hs
@@ -0,0 +1,55 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
+-- | This module provides low-level integration with the @binary@ package and is
+-- likely to be modified in backwards-incompatible ways in the future.
+--
+-- Use the "Control.Proxy.Binary" module instead.
+
+module Control.Proxy.Binary.Internal
+  ( DecodingError(..)
+  , parseWith
+  ) where
+
+-------------------------------------------------------------------------------
+
+import qualified Data.ByteString              as BS
+import qualified Data.Binary                  as Bin
+import qualified Data.Binary.Get              as Bin
+import Control.Exception                      (Exception)
+import Data.Data                              (Data, Typeable)
+
+-------------------------------------------------------------------------------
+
+data DecodingError = DecodingError
+  { peConsumed :: Bin.ByteOffset -- ^Number of bytes consumed before the error.
+  , peMessage  :: String         -- ^Error message.
+  } deriving (Show, Eq, Data, Typeable)
+
+instance Exception DecodingError
+
+-------------------------------------------------------------------------------
+
+-- | Run a parser drawing input from the given monadic action as needed.
+parseWith
+  :: (Monad m, Bin.Binary r)
+  => m (Maybe BS.ByteString)
+  -- ^An action that will be executed to provide the parser with more input
+  -- as needed. If the action returns 'Nothing', then it's assumed no more
+  -- input is available.
+  -> Bin.Get r
+  -- ^Parser to run on the given input.
+  -> m (Either DecodingError r, Maybe BS.ByteString)
+  -- ^Either a parser error or a parsed result, together with any leftover.
+parseWith refill g = step $ Bin.runGetIncremental g
+  where
+    step (Bin.Partial k)   = step . k =<< refill
+    step (Bin.Done lo _ r) = return (Right r, mayInput lo)
+    step (Bin.Fail lo n m) = return (Left (DecodingError n m), mayInput lo)
+{-# INLINABLE parseWith #-}
+
+-- | Wrap @a@ in 'Just' if not-null. Otherwise, 'Nothing'.
+mayInput :: BS.ByteString -> Maybe BS.ByteString
+mayInput x | BS.null x = Nothing
+           | otherwise = Just x
+{-# INLINE mayInput #-}
+
