diff --git a/ipython-kernel.cabal b/ipython-kernel.cabal
--- a/ipython-kernel.cabal
+++ b/ipython-kernel.cabal
@@ -1,5 +1,5 @@
 name:                ipython-kernel
-version:             0.6.0.0
+version:             0.6.1.0
 synopsis:            A library for creating kernels for IPython frontends
 
 description:         ipython-kernel is a library for communicating with frontends for the interactive IPython framework. It is used extensively in IHaskell, the interactive Haskell environment.
@@ -27,12 +27,10 @@
   exposed-modules: IHaskell.IPython.Kernel
                    IHaskell.IPython.Types
                    IHaskell.IPython.ZeroMQ
-                   IHaskell.IPython.Stdin
                    IHaskell.IPython.Message.Writer
                    IHaskell.IPython.Message.Parser
                    IHaskell.IPython.Message.UUID
                    IHaskell.IPython.EasyKernel
-  -- other-modules:       
   other-extensions:    OverloadedStrings
   hs-source-dirs:      src
   default-language:    Haskell2010
@@ -47,12 +45,10 @@
                        tar             >=0.4.0.1,
                        text            >=0.11,
                        transformers    >=0.3,
-                       unix            >=2.6,
                        uuid            >=1.3,
                        zeromq4-haskell >=0.1,
                        SHA             >=1.6
 
-
 -- Example program
 executable simple-calc-example
   hs-source-dirs: examples
@@ -64,6 +60,6 @@
                   parsec         >=3.1,
                   text           >=0.11,
                   transformers   >=0.3
-                  
+
   if !flag(examples)
     buildable: False
diff --git a/src/IHaskell/IPython/EasyKernel.hs b/src/IHaskell/IPython/EasyKernel.hs
--- a/src/IHaskell/IPython/EasyKernel.hs
+++ b/src/IHaskell/IPython/EasyKernel.hs
@@ -56,6 +56,7 @@
 
 import           IHaskell.IPython.Kernel
 import           IHaskell.IPython.Message.UUID as UUID
+import           IHaskell.IPython.Types
 
 import           System.Directory (createDirectoryIfMissing, doesDirectoryExist, doesFileExist,
                                    getHomeDirectory)
@@ -89,7 +90,7 @@
          , completion :: T.Text -> T.Text -> Int -> Maybe ([T.Text], T.Text, T.Text)
          -- | Return the information or documentation for its argument. The returned tuple consists of the
          -- name, the documentation, and the type, respectively.
-         , objectInfo :: T.Text -> Maybe (T.Text, T.Text, T.Text)
+         , inspectInfo :: T.Text -> Maybe (T.Text, T.Text, T.Text)
          -- | Execute a cell. The arguments are the contents of the cell, an IO action that will clear the
          -- current intermediate output, and an IO action that will add a new item to the intermediate
          -- output. The result consists of the actual result, the status to be sent to IPython, and the
@@ -155,7 +156,7 @@
 
 -- | Execute an IPython kernel for a config. Your 'main' action should call this as the last thing
 -- it does.
-easyKernel :: (MonadIO m)
+easyKernel :: MonadIO m
            => FilePath -- ^ The connection file provided by the IPython frontend
            -> KernelConfig m output result -- ^ The kernel configuration specifying how to react to
                                            -- messages
@@ -220,32 +221,17 @@
   return
     ExecuteReply
       { header = replyHeader
-      , pagerOutput = pagerOut
+      , pagerOutput = [DisplayData PlainText $ T.pack pagerOut]
       , executionCounter = fromIntegral counter
       , status = replyStatus
       }
 
 replyTo config _ _ req@CompleteRequest{} replyHeader =
   -- TODO: FIX
-  error "Unimplemented in IPython 3.0"
+  error "Completion: Unimplemented for IPython 3.0"
 
-replyTo config _ _ ObjectInfoRequest { objectName = obj } replyHeader =
-  return $
-    case objectInfo config obj of
-      Just (name, docs, ty) -> ObjectInfoReply
-        { header = replyHeader
-        , objectName = obj
-        , objectFound = True
-        , objectTypeString = ty
-        , objectDocString = docs
-        }
-      Nothing -> ObjectInfoReply
-        { header = replyHeader
-        , objectName = obj
-        , objectFound = False
-        , objectTypeString = ""
-        , objectDocString = ""
-        }
+replyTo _ _ _ InspectRequest{} _ = do
+  error $ "Inspection: Unimplemented for IPython 3.0"
 
 replyTo _ _ _ msg _ = do
   liftIO $ putStrLn "Unknown message: "
diff --git a/src/IHaskell/IPython/Message/Parser.hs b/src/IHaskell/IPython/Message/Parser.hs
--- a/src/IHaskell/IPython/Message/Parser.hs
+++ b/src/IHaskell/IPython/Message/Parser.hs
@@ -74,7 +74,7 @@
 parser KernelInfoRequestMessage = kernelInfoRequestParser
 parser ExecuteRequestMessage = executeRequestParser
 parser CompleteRequestMessage = completeRequestParser
-parser ObjectInfoRequestMessage = objectInfoRequestParser
+parser InspectRequestMessage = inspectRequestParser
 parser ShutdownRequestMessage = shutdownRequestParser
 parser InputReplyMessage = inputReplyParser
 parser CommOpenMessage = commOpenParser
@@ -139,11 +139,12 @@
   pos <- obj .: "cursor_pos"
   return $ CompleteRequest noHeader code pos
 
-objectInfoRequestParser :: LByteString -> Message
-objectInfoRequestParser = requestParser $ \obj -> do
-  oname <- obj .: "oname"
+inspectRequestParser :: LByteString -> Message
+inspectRequestParser = requestParser $ \obj -> do
+  code <- obj .: "code"
+  pos <- obj .: "cursor_pos"
   dlevel <- obj .: "detail_level"
-  return $ ObjectInfoRequest noHeader oname dlevel
+  return $ InspectRequest noHeader code pos dlevel
 
 shutdownRequestParser :: LByteString -> Message
 shutdownRequestParser = requestParser $ \obj -> do
diff --git a/src/IHaskell/IPython/Message/Writer.hs b/src/IHaskell/IPython/Message/Writer.hs
--- a/src/IHaskell/IPython/Message/Writer.hs
+++ b/src/IHaskell/IPython/Message/Writer.hs
@@ -29,25 +29,30 @@
       , "payload" .=
         if null pager
           then []
-          else [object ["source" .= string "page", "text" .= pager]]
+          else map mkObj pager
       , "user_variables" .= emptyMap
       , "user_expressions" .= emptyMap
       ]
+    where
+      mkObj o = object
+                  [ "source" .= string "page"
+                  , "line" .= Number 0
+                  , "data" .= object [displayDataToJson o]
+                  ]
   toJSON PublishStatus { executionState = executionState } =
     object ["execution_state" .= executionState]
   toJSON PublishStream { streamType = streamType, streamContent = content } =
     object ["data" .= content, "name" .= streamType]
   toJSON PublishDisplayData { source = src, displayData = datas } =
     object
-      ["source" .= src, "metadata" .=
-                        object [], "data" .=
-                                   object (map displayDataToJson datas)]
+      ["source" .= src, "metadata" .= object [], "data" .= object (map displayDataToJson datas)]
 
   toJSON PublishOutput { executionCount = execCount, reprText = reprText } =
     object
-      ["data" .=
-       object ["text/plain" .= reprText], "execution_count" .= execCount, "metadata" .=
-                                                                          object []]
+      [ "data" .= object ["text/plain" .= reprText]
+      , "execution_count" .= execCount
+      , "metadata" .= object []
+      ]
   toJSON PublishInput { executionCount = execCount, inCode = code } =
     object ["execution_count" .= execCount, "code" .= code]
   toJSON (CompleteReply _ matches start end metadata status) =
@@ -60,15 +65,14 @@
                       then string "ok"
                       else "error"
       ]
-  toJSON o@ObjectInfoReply{} =
+  toJSON i@InspectReply{} =
     object
-      [ "oname" .=
-        objectName o
-      , "found" .= objectFound o
-      , "ismagic" .= False
-      , "isalias" .= False
-      , "type_name" .= objectTypeString o
-      , "docstring" .= objectDocString o
+      [ "status" .= if inspectStatus i
+                      then string "ok"
+                      else "error"
+      , "data" .= object (map displayDataToJson . inspectData $ i)
+      , "metadata" .= object []
+      , "found" .= inspectStatus i
       ]
 
   toJSON ShutdownReply { restartPending = restart } =
diff --git a/src/IHaskell/IPython/Stdin.hs b/src/IHaskell/IPython/Stdin.hs
deleted file mode 100644
--- a/src/IHaskell/IPython/Stdin.hs
+++ /dev/null
@@ -1,113 +0,0 @@
-{-# LANGUAGE OverloadedStrings, DoAndIfThenElse #-}
-
--- | This module provides a way in which the Haskell standard input may be forwarded to the IPython
--- frontend and thus allows the notebook to use the standard input.
---
--- This relies on the implementation of file handles in GHC, and is generally unsafe and terrible.
--- However, it is difficult to find another way to do it, as file handles are generally meant to
--- point to streams and files, and not networked communication protocols.
---
--- In order to use this module, it must first be initialized with two things. First of all, in order
--- to know how to communicate with the IPython frontend, it must know the kernel profile used for
--- communication. For this, use @recordKernelProfile@ once the profile is known. Both this and
--- @recordParentHeader@ take a directory name where they can store this data.
---
--- Finally, the module must know what @execute_request@ message is currently being replied to (which
--- will request the input). Thus, every time the language kernel receives an @execute_request@
--- message, it should inform this module via @recordParentHeader@, so that the module may generate
--- messages with an appropriate parent header set. If this is not done, the IPython frontends will
--- not recognize the target of the communication.
---
--- Finally, in order to activate this module, @fixStdin@ must be called once. It must be passed the
--- same directory name as @recordParentHeader@ and @recordKernelProfile@. Note that if this is being
--- used from within the GHC API, @fixStdin@ /must/ be called from within the GHC session not from
--- the host code.
-module IHaskell.IPython.Stdin (fixStdin, recordParentHeader, recordKernelProfile) where
-
-import           Control.Concurrent
-import           Control.Applicative ((<$>))
-import           Control.Concurrent.Chan
-import           Control.Monad
-import           GHC.IO.Handle
-import           GHC.IO.Handle.Types
-import           System.IO
-import           System.Posix.IO
-import           System.IO.Unsafe
-import qualified Data.Map as Map
-
-import           IHaskell.IPython.Types
-import           IHaskell.IPython.ZeroMQ
-import           IHaskell.IPython.Message.UUID as UUID
-
-stdinInterface :: MVar ZeroMQStdin
-{-# NOINLINE stdinInterface #-}
-stdinInterface = unsafePerformIO newEmptyMVar
-
--- | Manipulate standard input so that it is sourced from the IPython frontend. This function is
--- build on layers of deep magical hackery, so be careful modifying it.
-fixStdin :: String -> IO ()
-fixStdin dir = do
-  -- Initialize the stdin interface.
-  profile <- read <$> readFile (dir ++ "/.kernel-profile")
-  interface <- serveStdin profile
-  putMVar stdinInterface interface
-  void $ forkIO $ stdinOnce dir
-
-stdinOnce :: String -> IO ()
-stdinOnce dir = do
-  -- Create a pipe using and turn it into handles.
-  (readEnd, writeEnd) <- createPipe
-  newStdin <- fdToHandle readEnd
-  stdinInput <- fdToHandle writeEnd
-  hSetBuffering newStdin NoBuffering
-  hSetBuffering stdinInput NoBuffering
-
-  -- Store old stdin and swap in new stdin.
-  oldStdin <- hDuplicate stdin
-  hDuplicateTo newStdin stdin
-
-  loop stdinInput oldStdin newStdin
-
-  where
-    loop stdinInput oldStdin newStdin = do
-      let FileHandle _ mvar = stdin
-      threadDelay $ 150 * 1000
-      empty <- isEmptyMVar mvar
-      if not empty
-        then loop stdinInput oldStdin newStdin
-        else do
-          line <- getInputLine dir
-          hPutStr stdinInput $ line ++ "\n"
-          loop stdinInput oldStdin newStdin
-
--- | Get a line of input from the IPython frontend.
-getInputLine :: String -> IO String
-getInputLine dir = do
-  StdinChannel req rep <- readMVar stdinInterface
-
-  -- Send a request for input.
-  uuid <- UUID.random
-  parentHeader <- read <$> readFile (dir ++ "/.last-req-header")
-  let header = MessageHeader
-        { username = username parentHeader
-        , identifiers = identifiers parentHeader
-        , parentHeader = Just parentHeader
-        , messageId = uuid
-        , sessionId = sessionId parentHeader
-        , metadata = Map.fromList []
-        , msgType = InputRequestMessage
-        }
-  let msg = RequestInput header ""
-  writeChan req msg
-
-  -- Get the reply.
-  InputReply _ value <- readChan rep
-  return value
-
-recordParentHeader :: String -> MessageHeader -> IO ()
-recordParentHeader dir header =
-  writeFile (dir ++ "/.last-req-header") $ show header
-
-recordKernelProfile :: String -> Profile -> IO ()
-recordKernelProfile dir profile =
-  writeFile (dir ++ "/.kernel-profile") $ show profile
diff --git a/src/IHaskell/IPython/Types.hs b/src/IHaskell/IPython/Types.hs
--- a/src/IHaskell/IPython/Types.hs
+++ b/src/IHaskell/IPython/Types.hs
@@ -38,6 +38,7 @@
 import qualified Data.Text as Text
 import qualified Data.Text.Encoding as Text
 import           Data.Text (Text)
+import qualified Data.String as S
 import           Data.Serialize
 import           IHaskell.IPython.Message.UUID
 import           GHC.Generics (Generic)
@@ -175,8 +176,8 @@
                  | InputMessage
                  | CompleteRequestMessage
                  | CompleteReplyMessage
-                 | ObjectInfoRequestMessage
-                 | ObjectInfoReplyMessage
+                 | InspectRequestMessage
+                 | InspectReplyMessage
                  | ShutdownRequestMessage
                  | ShutdownReplyMessage
                  | ClearOutputMessage
@@ -201,8 +202,8 @@
 showMessageType InputMessage = "pyin"
 showMessageType CompleteRequestMessage = "complete_request"
 showMessageType CompleteReplyMessage = "complete_reply"
-showMessageType ObjectInfoRequestMessage = "object_info_request"
-showMessageType ObjectInfoReplyMessage = "object_info_reply"
+showMessageType InspectRequestMessage = "inspect_request"
+showMessageType InspectReplyMessage = "inspect_reply"
 showMessageType ShutdownRequestMessage = "shutdown_request"
 showMessageType ShutdownReplyMessage = "shutdown_reply"
 showMessageType ClearOutputMessage = "clear_output"
@@ -228,8 +229,8 @@
       "pyin"                -> return InputMessage
       "complete_request"    -> return CompleteRequestMessage
       "complete_reply"      -> return CompleteReplyMessage
-      "object_info_request" -> return ObjectInfoRequestMessage
-      "object_info_reply"   -> return ObjectInfoReplyMessage
+      "inspect_request"     -> return InspectRequestMessage
+      "inspect_reply"       -> return InspectReplyMessage
       "shutdown_request"    -> return ShutdownRequestMessage
       "shutdown_reply"      -> return ShutdownReplyMessage
       "clear_output"        -> return ClearOutputMessage
@@ -272,7 +273,7 @@
                ExecuteReply
                  { header :: MessageHeader
                  , status :: ExecuteReplyStatus          -- ^ The status of the output.
-                 , pagerOutput :: String                 -- ^ The help string to show in the pager.
+                 , pagerOutput :: [DisplayData]          -- ^ The mimebundles to display in the pager.
                  , executionCounter :: Int               -- ^ The execution count, i.e. which output this is.
                  }
              |
@@ -325,20 +326,22 @@
                  , completionStatus :: Bool
                  }
              |
-               ObjectInfoRequest
+               InspectRequest
                  { header :: MessageHeader
-                 -- | Name of object being searched for.
-                 , objectName :: Text
+                 -- | The code context in which introspection is requested
+                 , inspectCode :: Text
+                 -- | Position of the cursor in unicode characters. json field @cursor_pos@
+                 , inspectCursorPos :: Int
                  -- | Level of detail desired (defaults to 0). 0 is equivalent to foo?, 1 is equivalent to foo??.
                  , detailLevel :: Int
                  }
              |
-               ObjectInfoReply
+               InspectReply
                  { header :: MessageHeader
-                 , objectName :: Text           -- ^ Name of object which was searched for.
-                 , objectFound :: Bool          -- ^ Whether the object was found.
-                 , objectTypeString :: Text     -- ^ Object type.
-                 , objectDocString :: Text
+                 -- | whether the request succeeded or failed
+                 , inspectStatus :: Bool
+                 -- | @inspectData@ can be empty if nothing is found
+                 , inspectData :: [DisplayData]
                  }
              |
                ShutdownRequest
@@ -421,7 +424,7 @@
 replyType KernelInfoRequestMessage = Just KernelInfoReplyMessage
 replyType ExecuteRequestMessage = Just ExecuteReplyMessage
 replyType CompleteRequestMessage = Just CompleteReplyMessage
-replyType ObjectInfoRequestMessage = Just ObjectInfoReplyMessage
+replyType InspectRequestMessage = Just InspectReplyMessage
 replyType ShutdownRequestMessage = Just ShutdownReplyMessage
 replyType HistoryRequestMessage = Just HistoryReplyMessage
 replyType _ = Nothing
diff --git a/src/IHaskell/IPython/ZeroMQ.hs b/src/IHaskell/IPython/ZeroMQ.hs
--- a/src/IHaskell/IPython/ZeroMQ.hs
+++ b/src/IHaskell/IPython/ZeroMQ.hs
@@ -194,7 +194,11 @@
 sendMessage :: Sender a => Bool -> ByteString -> Socket a -> Message -> IO ()
 sendMessage _ _ _ SendNothing = return ()
 sendMessage debug hmacKey socket message = do
-  when debug $ print message
+  when debug $ do
+    putStr "Message: "
+    print message
+    putStr "Sent: "
+    print content
 
   -- Send all pieces of the message.
   mapM_ sendPiece idents
