diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,6 +2,18 @@
 
 ## Unreleased changes
 
+## 0.8.0.0
+
+Fork `http2-client-grpc` to drop dependency on `proto-lens`.
+
+## 0.6.0.0
+
+Update to http2-client-0.9.0.0
+
+## 0.5.0.4
+
+Use proto-lens-0.4.0.0, this change is package-list incompatible but requires no code change.
+
 ## 0.5.0.3
 
 Add helpers for new bidirectional and general streams.
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright Author name here (c) 2017
+Copyright Lucas Di Cioccio (c) 2017
 
 All rights reserved.
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,75 +1,3 @@
 # http2-client-grpc
 
-A native HTTP2 gRPC client library using `proto-lens` and `http2-client`.
-
-## Summary
-
-This project provides a library that leverages the code generated using
-proto-lens (in particular, proto-lens-protoc) to implement the client-side of
-gRPC services.
-
-## Usage
-
-### Prerequisites
-
-In addition to a working Haskell dev environment, you need to:
-- build the `proto-lens-protoc` executable (`proto-lens`)
-- install the `protoc` executable
-
-### Adding .proto files to a Haskell package
-
-In order to run gRPC:
-
-- generate the `Proto` stubs in some `gen` directory
-
-A single `protoc` invocation may be enough for both Proto and GRPC outputs:
-
-```bash
-protoc  "--plugin=protoc-gen-haskell-protolens=${protolens}" \
-    --haskell-protolens_out=./gen \
-    -I "${protodir1} \
-    -I "${protodir2} \
-    ${first.proto} \
-    ${second.proto}
-```
-
-- add the `gen` sourcedir for the generated to your .cabal/package.yaml file (cf. 'hs-source-dirs').
-- add the generated Proto modules to the 'exposed-modules' (or 'other-modules') keys
-
-A reliable way to list the module names is the following bash invocation:
-
-```bash
-find gen -name "*.hs" | sed -e 's/gen\///' | sed -e 's/\.hs$//' | tr '/' '.'
-```
-
-Unlike `proto-lens`, this project does not yet provide a modified `Setup.hs`.
-As a result, we cannot automate these steps from within Cabal/Stack. Hence,
-you'll have to automate these steps outside your Haskell toolchain.
-
-## Calling a GRPC service
-
-In short, use `http2-client` with the `Network.GRPC.call` function and let the types guide you.
-
-### Example
-
-You'll find an example leveraging the awesome `grpcb.in` service at https://github.com/lucasdicioccio/http2-client-grpc-example .
-
-### gRPC service mapping
-
-The Protobuf format specifies the notion of Service which can have one or more
-RPCs.  The gRPC protocal maps these services onto HTTP2 headers and HTTP2
-frames.  In general, gRPC implementation generate one inlined function per RPC.
-This implementation differs by decoupling the HTTP2 transport and leveraging
-generics to provide generic functions. This design allows the
-`Network.GRPC.call` to be type safe and multi-usage. For instance, you can wrap
-this function with whatever metrics/benchmark code and have all your RPC calls
-be monitored in a uniform way.
-
-## Status
-
-This library is currently an early-stage library. Expect breaking changes.
-
-## Next steps
-
-- provide function to map raw results into commonly-understood GRPC errors
-- (nice-to-have) support effectful compression (Zlib pure compression is supported)
+A native HTTP2 gRPC client library using `http2-client`.
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,3 +1,2 @@
-import Data.ProtoLens.Setup
-
-main = defaultMain "."
+import Distribution.Simple
+main = defaultMain
diff --git a/http2-client-grpc.cabal b/http2-client-grpc.cabal
--- a/http2-client-grpc.cabal
+++ b/http2-client-grpc.cabal
@@ -1,13 +1,13 @@
 name:                http2-client-grpc
-version:             0.5.0.4
+version:             0.8.0.0
 synopsis:            Implement gRPC-over-HTTP2 clients.
-description:         A gRPC over http2-client using proto-lens to generate client code.
-homepage:            https://github.com/lucasdicioccio/http2-client-grpc#readme
+description:         A gRPC over http2-client.
+homepage:            https://github.com/haskell-grpc-native/http2-grpc-haskell/blob/master/http2-client-grpc/README.md
 license:             BSD3
 license-file:        LICENSE
-author:              Lucas DiCioccio
+author:              Lucas DiCioccio, Alejandro Serrano
 maintainer:          lucas@dicioccio.fr
-copyright:           2017 Lucas DiCioccio
+copyright:           2017 - 2019 Lucas DiCioccio, Alejandro Serrano
 category:            Network
 build-type:          Simple
 extra-source-files:  README.md Changelog.md
@@ -20,16 +20,16 @@
   build-depends:       base >= 4.11 && < 5
                      , async >= 2.2 && < 2.3
                      , binary >= 0.8 && < 0.9
-                     , bytestring >= 0.10.8 && < 0.10.9
+                     , bytestring >= 0.10.8 && < 0.11
                      , case-insensitive >= 1.2.0 && < 1.3
                      , data-default-class >= 0.1 && <0.2
-                     , lens >= 4.16 && < 4.17
-                     , http2 >= 1.6 && < 1.7
-                     , http2-client >= 0.8 && < 0.9
-                     , http2-grpc-types >= 0.3 && < 0.4
-                     , proto-lens >= 0.4 && < 0.5
+                     , lifted-async >= 0.10 && < 0.11
+                     , lifted-base >= 0.2 && < 0.3
+                     , http2 >= 1.6 && < 2.1
+                     , http2-client >= 0.9 && < 0.10
+                     , http2-grpc-types >= 0.5 && < 0.6
                      , text >= 1.2 && < 1.3
-                     , tls >= 1.4 && < 1.5
+                     , tls >= 1.4 && < 1.6
   default-language:    Haskell2010
 
 test-suite http2-client-grpc-test
@@ -43,4 +43,4 @@
 
 source-repository head
   type:     git
-  location: https://github.com/lucasdicioccio/http2-client-grpc
+  location: https://github.com/haskell-grpc-native/http2-grpc-haskell
diff --git a/src/Network/GRPC/Client.hs b/src/Network/GRPC/Client.hs
--- a/src/Network/GRPC/Client.hs
+++ b/src/Network/GRPC/Client.hs
@@ -47,8 +47,7 @@
 -- inspiration from the existing RPC functions and learn how to write one.
 module Network.GRPC.Client (
   -- * Building blocks.
-    RPC(..)
-  , RPCCall(..)
+    RPCCall(..)
   , CIHeaderList
   , Authority
   , Timeout(..)
@@ -81,9 +80,9 @@
   , HeaderList
   ) where
 
-import Control.Concurrent.Async (concurrently)
+import Control.Concurrent.Async.Lifted (concurrently)
 import Control.Exception (SomeException, Exception(..), throwIO)
-import Data.ByteString.Char8 (unpack)
+import Control.Monad.IO.Class (liftIO)
 import Data.ByteString.Lazy (toStrict)
 import Data.Binary.Builder (toLazyByteString)
 import Data.Binary.Get (Decoder(..), pushChunk, pushEndOfInput)
@@ -92,8 +91,6 @@
 import Data.CaseInsensitive (CI)
 import qualified Data.CaseInsensitive as CI
 import Data.Monoid ((<>))
-import Data.ProtoLens.Service.Types (Service(..), HasMethod, HasMethodImpl(..), StreamingType(..))
-import GHC.TypeLits (Symbol)
 
 import Network.GRPC.HTTP2.Types
 import Network.GRPC.HTTP2.Encoding
@@ -114,7 +111,7 @@
 -- - 1st item: initial HTTP2 response
 -- - 2nd item: second (trailers) HTTP2 response
 -- - 3rd item: proper gRPC answer
-type RawReply a = Either ErrorCode (CIHeaderList, Maybe CIHeaderList, (Either String a))
+type RawReply a = Either ErrorCode (CIHeaderList, Maybe CIHeaderList, Either String a)
 
 -- | gRPC disables HTTP2 push-promises.
 --
@@ -124,11 +121,14 @@
 
 -- | http2-client handler for push promise.
 throwOnPushPromise :: PushPromiseHandler
-throwOnPushPromise _ _ _ _ _ = throwIO UnallowedPushPromiseReceived
+throwOnPushPromise _ _ _ _ _ = lift $ throwIO UnallowedPushPromiseReceived
 
 -- | Wait for an RPC reply.
-waitReply :: (Service s, HasMethod s m) => RPC s m -> Decoding -> Http2Stream -> IncomingFlowControl -> IO (RawReply (MethodOutput s m))
-waitReply rpc decoding stream flowControl = do
+waitReply
+  :: (GRPCOutput r o)
+  => r -> Decoding -> Http2Stream -> IncomingFlowControl
+  -> ClientIO (RawReply o)
+waitReply rpc decoding stream flowControl =
     format . fromStreamResult <$> waitStream stream flowControl throwOnPushPromise
   where
     decompress = _getDecodingCompression decoding
@@ -140,8 +140,10 @@
              -- presence of a message indicate an error
              -- TODO: double check this is true in general
              case lookup grpcMessageH hdrs2 of
-               Nothing     -> fromDecoder $ pushEndOfInput $ flip pushChunk dat $ decodeOutput rpc decompress
-               Just errMsg -> Left $ unpack errMsg
+               Nothing     -> fromDecoder $ pushEndOfInput
+                                          $ flip pushChunk dat
+                                          $ decodeOutput rpc decompress
+               Just errMsg -> Left $ ByteString.unpack errMsg
 
        return (hdrs2, trls2, res)
 
@@ -150,27 +152,25 @@
 
 -- | Exception raised when a ServerStreaming RPC results in a decoding
 -- error.
-data StreamReplyDecodingError = StreamReplyDecodingError String deriving Show
+newtype StreamReplyDecodingError = StreamReplyDecodingError String deriving Show
 instance Exception StreamReplyDecodingError where
 
 -- | Exception raised when a ServerStreaming RPC results in an invalid
 -- state machine.
-data InvalidState = InvalidState String
-  deriving Show
+newtype InvalidState = InvalidState String deriving Show
 instance Exception InvalidState where
 
 -- | Newtype helper used to uniformize all type of streaming modes when
 -- passing arguments to the 'open' call.
-newtype RPCCall s (m ::Symbol) a = RPCCall {
-    runRPC :: Http2Client -> Http2Stream -> IncomingFlowControl -> OutgoingFlowControl -> Encoding -> Decoding -> IO a
+data RPCCall r a = RPCCall {
+    rpcFromCall :: r
+  , runRPC :: Http2Client -> Http2Stream
+           -> IncomingFlowControl -> OutgoingFlowControl
+           -> Encoding -> Decoding -> ClientIO a
   }
 
--- | Helper to get the proxy object from an RPCCall.
-rpcFromCall :: RPCCall s m a -> RPC s m
-rpcFromCall _ = RPC
-
 -- | Main handler to perform gRPC calls to a service.
-open :: (Service s, HasMethod s m)
+open :: (IsRPC r)
      => Http2Client
      -- ^ A connected HTTP2 client.
      -> Authority
@@ -183,9 +183,9 @@
      -- ^ Compression used for encoding.
      -> Decoding
      -- ^ Compression allowed for decoding
-     -> RPCCall s m a
+     -> RPCCall r a
      -- ^ The actual RPC handler.
-     -> IO (Either TooMuchConcurrency a)
+     -> ClientIO (Either TooMuchConcurrency a)
 open conn authority extraheaders timeout encoding decoding call = do
     let rpc = rpcFromCall call
     let compress = _getEncodingCompression encoding
@@ -202,35 +202,34 @@
                   ] <> extraheaders
     withHttp2Stream conn $ \stream ->
         let
-            initStream = headers stream request (setEndHeader)
-            handler isfc osfc = do
-                (runRPC call) conn stream isfc osfc encoding decoding
+            initStream = headers stream request setEndHeader
+            handler isfc osfc = runRPC call conn stream isfc osfc encoding decoding
         in StreamDefinition initStream handler
 
 -- | gRPC call for Server Streaming.
 streamReply
-  :: (Service s, HasMethod s m, MethodStreamingType s m ~ 'ServerStreaming)
-  => RPC s m
+  :: (GRPCInput r i, GRPCOutput r o)
+  => r
   -- ^ RPC to call.
   -> a
   -- ^ An initial state.
-  -> MethodInput s m
+  -> i
   -- ^ The input.
-  -> (a -> HeaderList -> MethodOutput s m -> IO a)
+  -> (a -> HeaderList -> o -> ClientIO a)
   -- ^ A state-passing handler that is called with the message read.
-  -> RPCCall s m (a, HeaderList, HeaderList)
-streamReply rpc v0 req handler = RPCCall $ \conn stream isfc osfc encoding decoding -> do
+  -> RPCCall r (a, HeaderList, HeaderList)
+streamReply rpc v0 req handler = RPCCall rpc $ \conn stream isfc osfc encoding decoding ->
     let {
         loop v1 decode hdrs = _waitEvent stream >>= \case
-            (StreamPushPromiseEvent _ _ _) ->
-                throwIO UnallowedPushPromiseReceived
-            (StreamHeadersEvent _ trls) ->
+            StreamPushPromiseEvent {} ->
+                lift $ throwIO UnallowedPushPromiseReceived
+            StreamHeadersEvent _ trls ->
                 return (v1, hdrs, trls)
-            (StreamErrorEvent _ _) ->
-                throwIO (InvalidState "stream error")
-            (StreamDataEvent _ dat) -> do
-                _addCredit isfc (ByteString.length dat)
-                _ <- _consumeCredit isfc (ByteString.length dat)
+            StreamErrorEvent _ _ ->
+                lift $ throwIO (InvalidState "stream error")
+            StreamDataEvent _ dat -> do
+                liftIO $ _addCredit isfc (ByteString.length dat)
+                _ <- liftIO $ _consumeCredit isfc (ByteString.length dat)
                 _ <- _updateWindow isfc
                 handleAllChunks decoding v1 hdrs decode dat loop
     } in do
@@ -241,18 +240,18 @@
             StreamHeadersEvent _ hdrs ->
                 loop v0 (decodeOutput rpc decompress) hdrs
             _                         ->
-                throwIO (InvalidState "no headers")
+                lift $ throwIO (InvalidState "no headers")
   where
     handleAllChunks decoding v1 hdrs decode dat exitLoop =
        case pushChunk decode dat of
-           (Done unusedDat _ (Right val)) -> do
+           Done unusedDat _ (Right val) -> do
                v2 <- handler v1 hdrs val
                let decompress = _getDecodingCompression decoding
                handleAllChunks decoding v2 hdrs (decodeOutput rpc decompress) unusedDat exitLoop
-           (Done _ _ (Left err)) -> do
-               throwIO (StreamReplyDecodingError $ "done-error: " ++ err)
-           (Fail _ _ err)                 -> do
-               throwIO (StreamReplyDecodingError $ "fail-error: " ++ err)
+           Done _ _ (Left err) ->
+               lift $ throwIO (StreamReplyDecodingError $ "done-error: " ++ err)
+           Fail _ _ err ->
+               lift $ throwIO (StreamReplyDecodingError $ "fail-error: " ++ err)
            partial@(Partial _)    ->
                exitLoop v1 partial hdrs
 
@@ -262,15 +261,15 @@
 
 -- | gRPC call for Client Streaming.
 streamRequest
-  :: (Service s, HasMethod s m, MethodStreamingType s m ~ 'ClientStreaming)
-  => RPC s m
+  :: (GRPCInput r i, GRPCOutput r o)
+  => r
   -- ^ RPC to call.
   -> a
   -- ^ An initial state.
-  -> (a -> IO (a, Either StreamDone (CompressMode, MethodInput s m)))
+  -> (a -> ClientIO (a, Either StreamDone (CompressMode, i)))
   -- ^ A state-passing action to retrieve the next message to send to the server.
-  -> RPCCall s m (a, RawReply (MethodOutput s m))
-streamRequest rpc v0 handler = RPCCall $ \conn stream isfc streamFlowControl encoding decoding ->
+  -> RPCCall r (a, RawReply o)
+streamRequest rpc v0 handler = RPCCall  rpc$ \conn stream isfc streamFlowControl encoding decoding ->
     let ocfc = _outgoingFlowControl conn
         go v1 = do
             (v2, nextEvent) <- handler v1
@@ -279,7 +278,8 @@
                     let compress = case doCompress of
                             Compressed -> _getEncodingCompression encoding
                             Uncompressed -> uncompressed
-                    sendSingleMessage rpc msg (Encoding compress) id conn ocfc stream streamFlowControl
+                    sendSingleMessage rpc msg (Encoding compress) id
+                                      conn ocfc stream streamFlowControl
                     go v2
                 Left _ -> do
                     sendData conn stream setEndStream ""
@@ -289,23 +289,23 @@
 
 -- | Serialize and send a single message.
 sendSingleMessage
-  :: (Service s, HasMethod s m)
-  => RPC s m
-  -> MethodInput s m
+  :: (GRPCInput r i)
+  => r
+  -> i
   -> Encoding
   -> FlagSetter
   -> Http2Client
   -> OutgoingFlowControl
   -> Http2Stream
   -> OutgoingFlowControl
-  -> IO ()
+  -> ClientIO ()
 sendSingleMessage rpc msg encoding flagMod conn connectionFlowControl stream streamFlowControl = do
     let compress = _getEncodingCompression encoding
     let goUpload dat = do
             let !wanted = ByteString.length dat
             gotStream <- _withdrawCredit streamFlowControl wanted
             got       <- _withdrawCredit connectionFlowControl gotStream
-            _receiveCredit streamFlowControl (gotStream - got)
+            liftIO $ _receiveCredit streamFlowControl (gotStream - got)
             if got == wanted
             then
                 sendData conn stream flagMod dat
@@ -316,32 +316,32 @@
 
 -- | gRPC call for an unary request.
 singleRequest
-  :: (Service s, HasMethod s m)
-  => RPC s m
+  :: (GRPCInput r i, GRPCOutput r o)
+  => r
   -- ^ RPC to call.
-  -> MethodInput s m
+  -> i
   -- ^ RPC's input.
-  -> RPCCall s m (RawReply (MethodOutput s m))
-singleRequest rpc msg = RPCCall $ \conn stream isfc osfc encoding decoding -> do
+  -> RPCCall r (RawReply o)
+singleRequest rpc msg = RPCCall rpc $ \conn stream isfc osfc encoding decoding -> do
     let ocfc = _outgoingFlowControl conn
     sendSingleMessage rpc msg encoding setEndStream conn ocfc stream osfc
     waitReply rpc decoding stream isfc
 
 -- | Handler for received message.
-type HandleMessageStep s m a = HeaderList -> a -> MethodOutput s m -> IO a
+type HandleMessageStep i o a = HeaderList -> a -> o -> ClientIO a
 -- | Handler for received trailers.
-type HandleTrailersStep a = HeaderList -> a -> HeaderList -> IO a
+type HandleTrailersStep a = HeaderList -> a -> HeaderList -> ClientIO a
 
-data BiDiStep s m a =
+data BiDiStep i o a =
     Abort
   -- ^ Finalize and return the current state.
-  | SendInput !CompressMode !(MethodInput s m)
+  | SendInput !CompressMode !i
   -- ^ Sends a single message.
-  | WaitOutput (HandleMessageStep s m a) (HandleTrailersStep a)
+  | WaitOutput (HandleMessageStep i o a) (HandleTrailersStep a)
   -- ^ Wait for information from the server, handlers can modify the state.
 
 -- | State-based function.
-type RunBiDiStep s m a = a -> IO (a, BiDiStep s m a)
+type RunBiDiStep s meth a = a -> ClientIO (a, BiDiStep s meth a)
 
 -- | gRPC call for a stepped bidirectional stream.
 --
@@ -350,15 +350,15 @@
 -- See 'BiDiStep' and 'RunBiDiStep' to understand the type of programs one can
 -- write with this function.
 steppedBiDiStream
-  :: (Service s, HasMethod s m, MethodStreamingType s m ~ 'BiDiStreaming)
-  => RPC s m
+  :: (GRPCInput r i, GRPCOutput r o)
+  => r
   -- ^ RPC to call.
   -> a
   -- ^ An initial state.
-  -> RunBiDiStep s m a
+  -> RunBiDiStep i o a
   -- ^ The program.
-  -> RPCCall s m a
-steppedBiDiStream rpc v0 handler = RPCCall $ \conn stream isfc streamFlowControl encoding decoding ->
+  -> RPCCall r a
+steppedBiDiStream rpc v0 handler = RPCCall rpc $ \conn stream isfc streamFlowControl encoding decoding ->
     let ocfc = _outgoingFlowControl conn
         decompress = _getDecodingCompression decoding
         newDecoder = decodeOutput rpc decompress
@@ -372,49 +372,49 @@
                     Uncompressed -> uncompressed
             sendSingleMessage rpc msg (Encoding compress) id conn ocfc stream streamFlowControl
             handler v1 >>= goStep hdrs decode
-        goStep jhdrs@(Just hdrs) decode unchanged@(v1, WaitOutput handleMsg handleEof) = do
+        goStep jhdrs@(Just hdrs) decode unchanged@(v1, WaitOutput handleMsg handleEof) =
             _waitEvent stream >>= \case
-                (StreamPushPromiseEvent _ _ _) ->
-                    throwIO UnallowedPushPromiseReceived
-                (StreamHeadersEvent _ trls) -> do
+                StreamPushPromiseEvent {} ->
+                    lift $ throwIO UnallowedPushPromiseReceived
+                StreamHeadersEvent _ trls -> do
                     v2 <- handleEof hdrs v1 trls
                     -- TODO: consider failing the decoder here
                     handler v2 >>= goStep jhdrs newDecoder
-                (StreamErrorEvent _ _) ->
-                    throwIO (InvalidState "stream error")
-                (StreamDataEvent _ dat) -> do
-                    _addCredit isfc (ByteString.length dat)
-                    _ <- _consumeCredit isfc (ByteString.length dat)
+                StreamErrorEvent _ _ ->
+                    lift $ throwIO (InvalidState "stream error")
+                StreamDataEvent _ dat -> do
+                    liftIO $ _addCredit isfc (ByteString.length dat)
+                    _ <- liftIO $ _consumeCredit isfc (ByteString.length dat)
                     _ <- _updateWindow isfc
                     case pushChunk decode dat of
-                        (Done unusedDat _ (Right val)) -> do
+                        Done unusedDat _ (Right val) -> do
                             v2 <- handleMsg hdrs v1 val
                             handler v2 >>= goStep jhdrs (pushChunk newDecoder unusedDat)
-                        (Done _ _ (Left err)) -> do
-                            throwIO $ InvalidParse $ "done-err: " ++ err
-                        (Fail _ _ err)         ->
-                            throwIO $ InvalidParse $ "done-fail: " ++ err
-                        partial@(Partial _)    -> do
+                        Done _ _ (Left err) ->
+                            lift $ throwIO $ InvalidParse $ "done-err: " ++ err
+                        Fail _ _ err ->
+                            lift $ throwIO $ InvalidParse $ "done-fail: " ++ err
+                        partial@(Partial _) ->
                             goStep jhdrs partial unchanged
-        goStep Nothing decode unchanged = do
+        goStep Nothing decode unchanged =
             _waitEvent stream >>= \case
-                (StreamHeadersEvent _ hdrs) ->
+                StreamHeadersEvent _ hdrs ->
                    goStep (Just hdrs) decode unchanged
                 _ ->
-                   throwIO (InvalidState "no headers")
+                   lift $ throwIO (InvalidState "no headers")
 
     in handler v0 >>= goStep Nothing newDecoder
 
 -- | Exception raised when a BiDiStreaming RPC results in an invalid
 -- parse.
-data InvalidParse = InvalidParse String deriving Show
+newtype InvalidParse = InvalidParse String deriving Show
 instance Exception InvalidParse where
 
 -- | An event for the incoming loop of 'generalHandler'.
-data IncomingEvent s m a =
+data IncomingEvent o a =
     Headers HeaderList
   -- ^ The server sent some initial metadata with the headers.
-  | RecvMessage (MethodOutput s m)
+  | RecvMessage o
   -- ^ The server send a message.
   | Trailers HeaderList
   -- ^ The server send final metadata (the loop stops).
@@ -422,10 +422,10 @@
   -- ^ Something went wrong (the loop stops).
 
 -- | An event for the outgoing loop of 'generalHandler'.
-data OutgoingEvent s m b =
+data OutgoingEvent i b =
     Finalize
   -- ^ The client is done with the RPC (the loop stops).
-  | SendMessage CompressMode (MethodInput s m)
+  | SendMessage CompressMode i
   -- ^ The client sends a message to the server.
 
 -- | General RPC handler for decorrelating the handling of received
@@ -440,19 +440,19 @@
 -- and stops on Trailers or Invalid. The other loop waits for messages to send to
 -- the server or finalize and returns.
 generalHandler 
-  :: (Service s, HasMethod s m)
-  => RPC s m
+  :: (GRPCInput r i, GRPCOutput r o)
+  => r
   -- ^ RPC to call.
   -> a
   -- ^ An initial state for the incoming loop.
-  -> (a -> IncomingEvent s m a -> IO a)
+  -> (a -> IncomingEvent o a -> ClientIO a)
   -- ^ A state-passing function for the incoming loop.
   -> b
   -- ^ An initial state for the outgoing loop.
-  -> (b -> IO (b, OutgoingEvent s m b))
+  -> (b -> ClientIO (b, OutgoingEvent i b))
   -- ^ A state-passing function for the outgoing loop.
-  -> RPCCall s m (a,b)
-generalHandler rpc v0 handle w0 next = RPCCall $ \conn stream isfc osfc encoding decoding ->
+  -> RPCCall r (a,b)
+generalHandler rpc v0 handle w0 next = RPCCall rpc $ \conn stream isfc osfc encoding decoding ->
     go conn stream isfc osfc encoding decoding
   where
     go conn stream isfc osfc encoding decoding =
@@ -475,28 +475,28 @@
                     outGoingLoop v2
         incomingLoop Nothing decode v1 =
                 _waitEvent stream >>= \case
-                    (StreamHeadersEvent _ hdrs) ->
+                    StreamHeadersEvent _ hdrs ->
                        handle v1 (Headers hdrs) >>= incomingLoop (Just hdrs) decode
                     _ ->
                        handle v1 (Invalid $ toException $ InvalidState "no headers")
         incomingLoop jhdrs decode v1 =
             _waitEvent stream >>= \case
-                (StreamHeadersEvent _ hdrs) ->
+                StreamHeadersEvent _ hdrs ->
                     handle v1 (Trailers hdrs)
-                (StreamDataEvent _ dat) -> do
-                    _addCredit isfc (ByteString.length dat)
-                    _ <- _consumeCredit isfc (ByteString.length dat)
+                StreamDataEvent _ dat -> do
+                    liftIO $ _addCredit isfc (ByteString.length dat)
+                    _ <- liftIO $ _consumeCredit isfc (ByteString.length dat)
                     _ <- _updateWindow isfc
                     case pushChunk decode dat of
-                        (Done unusedDat _ (Right val)) ->
+                        Done unusedDat _ (Right val) ->
                             handle v1 (RecvMessage val) >>= incomingLoop jhdrs (pushChunk newDecoder unusedDat)
-                        partial@(Partial _)    -> do
+                        partial@(Partial _) ->
                             incomingLoop jhdrs partial v1
-                        (Done _ _ (Left err)) -> do
+                        Done _ _ (Left err) ->
                             handle v1 (Invalid $ toException $ InvalidParse $ "invalid-done-parse: " ++ err)
-                        (Fail _ _ err)         ->
+                        Fail _ _ err ->
                             handle v1 (Invalid $ toException $ InvalidParse $ "invalid-parse: " ++ err)
-                (StreamPushPromiseEvent _ _ _) ->
+                StreamPushPromiseEvent {} ->
                     handle v1 (Invalid $ toException UnallowedPushPromiseReceived)
-                (StreamErrorEvent _ _) ->
+                StreamErrorEvent {} ->
                     handle v1 (Invalid $ toException $ InvalidState "stream error")
diff --git a/src/Network/GRPC/Client/Helpers.hs b/src/Network/GRPC/Client/Helpers.hs
--- a/src/Network/GRPC/Client/Helpers.hs
+++ b/src/Network/GRPC/Client/Helpers.hs
@@ -2,6 +2,7 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE GADTs             #-}
 {-# LANGUAGE FlexibleContexts  #-}
+{-# LANGUAGE CPP               #-}
 
 -- | Set of helpers helping with writing gRPC clients with not much exposure of
 -- the http2-client complexity.
@@ -14,23 +15,22 @@
 -- are not planned in this library and should be added at higher-levels.
 module Network.GRPC.Client.Helpers where
 
-import Control.Lens
-import Control.Concurrent.Async (Async, async, cancel)
-import Control.Concurrent (threadDelay)
+import Control.Concurrent.Async.Lifted (Async, async, cancel)
+import Control.Concurrent.Lifted (threadDelay)
 import Control.Exception (throwIO)
 import Control.Monad (forever)
+import Control.Monad.IO.Class (liftIO)
 import qualified Data.ByteString.Char8 as ByteString
 import Data.ByteString.Char8 (ByteString)
 import Data.Default.Class (def)
-import Data.ProtoLens.Service.Types (Service(..), HasMethod, HasMethodImpl(..), StreamingType(..))
 import qualified Network.TLS as TLS
 import qualified Network.TLS.Extra.Cipher as TLS
 import Network.HPACK (HeaderList)
 
-import Network.HTTP2.Client (newHttp2FrameConnection, newHttp2Client, Http2Client(..), IncomingFlowControl(..), GoAwayHandler, FallBackFrameHandler, ignoreFallbackHandler, HostName, PortNumber, TooMuchConcurrency)
+import Network.HTTP2.Client (ClientIO, ClientError, newHttp2FrameConnection, newHttp2Client, Http2Client(..), IncomingFlowControl(..), GoAwayHandler, FallBackFrameHandler, ignoreFallbackHandler, HostName, PortNumber, TooMuchConcurrency)
 import Network.HTTP2.Client.Helpers (ping)
-import Network.GRPC.Client (RPC, open, singleRequest, streamReply, streamRequest, steppedBiDiStream, generalHandler, Authority, Timeout(..), StreamDone, CompressMode, RawReply, RunBiDiStep, IncomingEvent(..), OutgoingEvent(..))
-import Network.GRPC.HTTP2.Encoding (Compression, Encoding(..), Decoding(..), gzip)
+import Network.GRPC.Client
+import Network.GRPC.HTTP2.Encoding
 
 -- | A simplified gRPC Client connected via an HTTP2Client to a given server.
 -- Each call from one client will share similar headers, timeout, compression.
@@ -50,9 +50,9 @@
   }
 
 data BackgroundTasks = BackgroundTasks {
-    backgroundWindowUpdate :: Async ()
+    backgroundWindowUpdate :: Async (Either ClientError ())
   -- ^ Periodically give the server credit to use the connection.
-  , backgroundPing         :: Async ()
+  , backgroundPing         :: Async (Either ClientError ())
   -- ^ Periodically ping the server.
   }
 
@@ -82,7 +82,7 @@
 
 grpcClientConfigSimple :: HostName -> PortNumber -> UseTlsOrNot -> GrpcClientConfig
 grpcClientConfigSimple host port tls =
-    GrpcClientConfig host port [] (Timeout 3000) gzip (tlsSettings tls host port) throwIO ignoreFallbackHandler 5000000 1000000
+    GrpcClientConfig host port [] (Timeout 3000) gzip (tlsSettings tls host port) (liftIO . throwIO) ignoreFallbackHandler 5000000 1000000
 
 type UseTlsOrNot = Bool
 
@@ -98,10 +98,13 @@
                                                }
         , TLS.clientSupported            = def { TLS.supportedCiphers = TLS.ciphersuite_default }
         , TLS.clientDebug                = def
+#if MIN_VERSION_tls(1,5,0)
+        , TLS.clientEarlyData            = Nothing
+#endif
         }
 
 
-setupGrpcClient :: GrpcClientConfig -> IO GrpcClient
+setupGrpcClient :: GrpcClientConfig -> ClientIO GrpcClient
 setupGrpcClient config = do
   let host = _grpcClientConfigHost config
   let port = _grpcClientConfigPort config
@@ -125,7 +128,7 @@
   return $ GrpcClient cli authority headers timeout compression tasks
 
 -- | Cancels background tasks and closes the underlying HTTP2 client.
-close :: GrpcClient -> IO ()
+close :: GrpcClient -> ClientIO ()
 close grpc = do
     cancel $ backgroundPing $ _grpcClientBackground grpc
     cancel $ backgroundWindowUpdate $ _grpcClientBackground grpc
@@ -133,44 +136,33 @@
 
 -- | Run an unary query.
 rawUnary
-  :: (Service s, HasMethod s m)
-  => RPC s m
+  :: (GRPCInput r i, GRPCOutput r o)
+  => r
   -- ^ The RPC to call.
   -> GrpcClient
   -- ^ An initialized client.
-  -> MethodInput s m
+  -> i
   -- ^ The input.
-  -> IO (Either TooMuchConcurrency (RawReply (MethodOutput s m)))
+  -> ClientIO (Either TooMuchConcurrency (RawReply o))
 rawUnary rpc (GrpcClient client authority headers timeout compression _) input =
     let call = singleRequest rpc input
     in open client authority headers timeout (Encoding compression) (Decoding compression) call
 
--- | Prism helper to unpack an unary gRPC call output.
---
--- @ out <- rawUnary rpc grpc method
---   print $ out ^? unaryOutput . somefield
--- @
-unaryOutput
-  :: (Applicative f, Field3 a1 b1 (Either c1 a2) (Either c1 b2)) =>
-     (a2 -> f b2)
-     -> Either c2 (Either c3 a1) -> f (Either c2 (Either c3 b1))
-unaryOutput = _Right . _Right . _3 . _Right
-
 -- | Calls for a server stream of requests.
 rawStreamServer
-  :: (Service s, HasMethod s m, MethodStreamingType s m ~ 'ServerStreaming)
-  => RPC s m
+  :: (GRPCInput r i, GRPCOutput r o)
+  => r
   -- ^ The RPC to call.
   -> GrpcClient
   -- ^ An initialized client.
   -> a
   -- ^ An initial state.
-  -> MethodInput s m
+  -> i
   -- ^ The input of the stream request.
-  -> (a -> HeaderList -> MethodOutput s m -> IO a)
+  -> (a -> HeaderList -> o -> ClientIO a)
   -- ^ A state-passing handler called for each server-sent output.
   -- Headers are repeated for convenience but are the same for every iteration.
-  -> IO (Either TooMuchConcurrency (a, HeaderList, HeaderList))
+  -> ClientIO (Either TooMuchConcurrency (a, HeaderList, HeaderList))
 rawStreamServer rpc (GrpcClient client authority headers timeout compression _) v0 input handler =
     let call = streamReply rpc v0 input handler
     in open client authority headers timeout (Encoding compression) (Decoding compression) call
@@ -180,16 +172,16 @@
 -- Messages are submitted to the HTTP2 underlying client and hence this
 -- function can block until the HTTP2 client has some network credit.
 rawStreamClient
-  :: (Service s, HasMethod s m, MethodStreamingType s m ~ 'ClientStreaming)
-  => RPC s m
+  :: (GRPCInput r i, GRPCOutput r o)
+  => r
   -- ^ The RPC to call.
   -> GrpcClient
   -- ^ An initialized client.
   -> a
   -- ^ An initial state.
-  -> (a -> IO (a, Either StreamDone (CompressMode, MethodInput s m)))
+  -> (a -> ClientIO (a, Either StreamDone (CompressMode, i)))
   -- ^ A state-passing step function to decide the next message.
-  -> IO (Either TooMuchConcurrency (a, (RawReply (MethodOutput s m))))
+  -> ClientIO (Either TooMuchConcurrency (a, RawReply o))
 rawStreamClient rpc (GrpcClient client authority headers timeout compression _) v0 getNext =
     let call = streamRequest rpc v0 getNext
     in open client authority headers timeout (Encoding compression) (Decoding compression) call
@@ -200,16 +192,16 @@
 -- protocols, that is, when after sending a message a client can know how many
 -- messages to wait for before sending the next message.
 rawSteppedBidirectional
-  :: (Service s, HasMethod s m, MethodStreamingType s m ~ 'BiDiStreaming)
-  => RPC s m
+  :: (GRPCInput r i, GRPCOutput r o)
+  => r
   -- ^ The RPC to call.
   -> GrpcClient
   -- ^ An initialized client.
   -> a
   -- ^ An initial state.
-  -> RunBiDiStep s m a
+  -> RunBiDiStep i o a
   -- ^ The sequential program to iterate between sending and receiving messages.
-  -> IO (Either TooMuchConcurrency a)
+  -> ClientIO (Either TooMuchConcurrency a)
 rawSteppedBidirectional rpc (GrpcClient client authority headers timeout compression _) v0 handler =
     let call = steppedBiDiStream rpc v0 handler
     in open client authority headers timeout (Encoding compression) (Decoding compression) call
@@ -219,20 +211,20 @@
 -- This handler allows to concurrently write messages and wait for incoming
 -- messages.
 rawGeneralStream
-  :: (Service s, HasMethod s m)
-  => RPC s m
+  :: (GRPCInput r i, GRPCOutput r o)
+  => r
   -- ^ The RPC to call.
   -> GrpcClient
   -- ^ An initialized client.
   -> a
   -- ^ An initial state for the incoming loop.
-  -> (a -> IncomingEvent s m a -> IO a)
+  -> (a -> IncomingEvent o a -> ClientIO a)
   -- ^ A state-passing function for the incoming loop.
   -> b
   -- ^ An initial state for the outgoing loop.
-  -> (b -> IO (b, OutgoingEvent s m b))
+  -> (b -> ClientIO (b, OutgoingEvent i b))
   -- ^ A state-passing function for the ougoing loop.
-  -> IO (Either TooMuchConcurrency (a,b))
+  -> ClientIO (Either TooMuchConcurrency (a,b))
 rawGeneralStream rpc (GrpcClient client authority headers timeout compression _) v0 handler w0 next =
     let call = generalHandler rpc v0 handler w0 next
     in open client authority headers timeout (Encoding compression) (Decoding compression) call
