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.8.2.0
+version:             0.8.3.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.
@@ -46,6 +46,7 @@
                        mtl             >=2.1,
                        text            >=0.11,
                        transformers    >=0.3,
+                       unordered-containers >= 0.2.5,
                        uuid            >=1.3,
                        zeromq4-haskell >=0.1,
                        SHA             >=1.6
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
@@ -1,4 +1,5 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
+{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-name-shadowing #-}
 
 -- | Description : Parsing messages received from IPython
 --
@@ -7,13 +8,17 @@
 -- the low-level 0MQ interface.
 module IHaskell.IPython.Message.Parser (parseMessage) where
 
-import           Data.Aeson ((.:), (.:?), (.!=), decode, Result(..), Object)
 import           Control.Applicative ((<|>), (<$>), (<*>))
-import           Data.Aeson.Types (parse)
-import           Data.ByteString
+import           Data.Aeson ((.:), (.:?), (.!=), decode, Result(..), Object, Value(..))
+import           Data.Aeson.Types (parse, parseEither)
+import           Data.ByteString hiding (unpack)
+import qualified Data.ByteString.Lazy as Lazy
+import           Data.HashMap.Strict as HM
 import           Data.Map (Map)
+import           Data.Maybe (fromMaybe)
 import           Data.Text (Text)
-import qualified Data.ByteString.Lazy as Lazy
+import           Data.Text (Text, unpack)
+import           Debug.Trace
 import           IHaskell.IPython.Types
 
 type LByteString = Lazy.ByteString
@@ -72,7 +77,13 @@
        -> LByteString -> Message -- ^ The parser that converts the body into a message. This message
                                  -- should have an undefined header.
 parser KernelInfoRequestMessage = kernelInfoRequestParser
+parser ExecuteInputMessage = executeInputParser
 parser ExecuteRequestMessage = executeRequestParser
+parser ExecuteReplyMessage = executeReplyParser
+parser ExecuteErrorMessage = executeErrorParser
+parser ExecuteResultMessage = executeResultParser
+parser DisplayDataMessage = displayDataParser
+parser IsCompleteRequestMessage = isCompleteRequestParser
 parser CompleteRequestMessage = completeRequestParser
 parser InspectRequestMessage = inspectRequestParser
 parser ShutdownRequestMessage = shutdownRequestParser
@@ -81,6 +92,11 @@
 parser CommDataMessage = commDataParser
 parser CommCloseMessage = commCloseParser
 parser HistoryRequestMessage = historyRequestParser
+parser StatusMessage = statusMessageParser
+parser StreamMessage = streamMessageParser
+parser InputMessage = inputMessageParser
+parser OutputMessage = outputMessageParser
+parser ClearOutputMessage = clearOutputMessageParser
 parser other = error $ "Unknown message type " ++ show other
 
 -- | Parse a kernel info request. A kernel info request has no auxiliary information, so ignore the
@@ -88,6 +104,13 @@
 kernelInfoRequestParser :: LByteString -> Message
 kernelInfoRequestParser _ = KernelInfoRequest { header = noHeader }
 
+-- | Parse an execute_input response. Fields used are:
+executeInputParser :: LByteString -> Message
+executeInputParser = requestParser $ \obj -> do
+  code <- obj .: "code"
+  executionCount <- obj .: "execution_count"
+  return $ ExecuteInput noHeader code executionCount
+
 -- | Parse an execute request. Fields used are:
 --  1. "code": the code to execute.
 --  2. "silent": whether to execute silently.
@@ -114,9 +137,48 @@
     , getUserExpressions = []
     }
 
-requestParser parser content = parsed
+-- | Parse an execute reply
+executeReplyParser :: LByteString -> Message
+executeReplyParser = requestParser $ \obj -> do
+  status <- obj .: "status"
+  executionCount <- obj .: "execution_count"
+  return $ ExecuteReply noHeader status [] executionCount
+
+-- | Parse an execute reply
+executeErrorParser :: LByteString -> Message
+executeErrorParser = requestParser $ \obj -> do
+  -- executionCount <- obj .: "execution_count"
+  traceback <- obj .: "traceback"
+  ename <- obj .: "ename"
+  evalue <- obj .: "evalue"
+  return $ ExecuteError noHeader [] traceback ename evalue
+
+makeDisplayDatas :: Object -> [DisplayData]
+makeDisplayDatas dataDict = [DisplayData (read $ unpack mimeType) content | (mimeType, String content) <- HM.toList
+                                                                                                            dataDict]
+
+-- | Parse an execute result
+executeResultParser :: LByteString -> Message
+executeResultParser = requestParser $ \obj -> do
+  executionCount <- obj .: "execution_count"
+  dataDict :: Object <- obj .: "data"
+  let displayDatas = makeDisplayDatas dataDict
+  metadataDict <- obj .: "metadata"
+  return $ ExecuteResult noHeader displayDatas metadataDict executionCount
+
+-- | Parse a display data message
+displayDataParser :: LByteString -> Message
+displayDataParser = requestParser $ \obj -> do
+  dataDict :: Object <- obj .: "data"
+  let displayDatas = makeDisplayDatas dataDict
+  maybeSource <- obj .:? "source"
+  return $ PublishDisplayData noHeader (fromMaybe "" maybeSource) displayDatas
+
+requestParser parser content =
+  case parseEither parser decoded of
+    Right parsed -> parsed
+    Left err     -> trace ("Parse error: " ++ show err) SendNothing
   where
-    Success parsed = parse parser decoded
     Just decoded = decode content
 
 historyRequestParser :: LByteString -> Message
@@ -132,6 +194,48 @@
           "tail"   -> HistoryTail
           "search" -> HistorySearch
           str      -> error $ "Unknown history access type: " ++ str
+
+statusMessageParser :: LByteString -> Message
+statusMessageParser = requestParser $ \obj -> do
+  execution_state <- obj .: "execution_state"
+  return $ PublishStatus noHeader execution_state
+
+streamMessageParser :: LByteString -> Message
+streamMessageParser = requestParser $ \obj -> do
+  streamType <- obj .: "name"
+  streamContent <- obj .: "text"
+  return $ PublishStream noHeader streamType streamContent
+
+inputMessageParser :: LByteString -> Message
+inputMessageParser = requestParser $ \obj -> do
+  code <- obj .: "code"
+  executionCount <- obj .: "execution_count"
+  return $ Input noHeader code executionCount
+
+getDisplayDatas Nothing = []
+getDisplayDatas (Just dataDict) = makeDisplayDatas dataDict
+
+outputMessageParser :: LByteString -> Message
+outputMessageParser = requestParser $ \obj -> do
+  -- Handle both "data" and "text" keys
+  maybeDataDict1 :: Maybe Object <- obj .:? "data"
+  let displayDatas1 = getDisplayDatas maybeDataDict1
+
+  maybeDataDict2 :: Maybe Object <- obj .:? "text"
+  let displayDatas2 = getDisplayDatas maybeDataDict2
+
+  executionCount <- obj .: "execution_count"
+  return $ Output noHeader (displayDatas1 ++ displayDatas2) executionCount
+
+clearOutputMessageParser :: LByteString -> Message
+clearOutputMessageParser = requestParser $ \obj -> do
+  wait <- obj .: "wait"
+  return $ ClearOutput noHeader wait
+
+isCompleteRequestParser :: LByteString -> Message
+isCompleteRequestParser = requestParser $ \obj -> do
+  code <- obj .: "code"
+  return $ IsCompleteRequest noHeader code
 
 completeRequestParser :: LByteString -> Message
 completeRequestParser = requestParser $ \obj -> do
diff --git a/src/IHaskell/IPython/Message/UUID.hs b/src/IHaskell/IPython/Message/UUID.hs
--- a/src/IHaskell/IPython/Message/UUID.hs
+++ b/src/IHaskell/IPython/Message/UUID.hs
@@ -3,10 +3,10 @@
 -- Generate, parse, and pretty print UUIDs for use with IPython.
 module IHaskell.IPython.Message.UUID (UUID, random, randoms, uuidToString) where
 
+import           Control.Applicative ((<$>), (<*>))
 import           Control.Monad (mzero, replicateM)
-import           Control.Applicative ((<$>))
-import           Data.Text (pack)
 import           Data.Aeson
+import           Data.Text (pack)
 import           Data.UUID.V4 (nextRandom)
 
 -- | A UUID (universally unique identifier).
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
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-name-shadowing -fno-warn-unused-matches #-}
 
 -- | Description : @ToJSON@ for Messages
 --
@@ -6,14 +7,10 @@
 module IHaskell.IPython.Message.Writer (ToJSON(..)) where
 
 import           Data.Aeson
+import           Data.Aeson.Types (Pair)
 import           Data.Map (Map)
-import           Data.Text (Text, pack)
 import           Data.Monoid (mempty)
-
-import qualified Data.ByteString.Lazy as L
-import qualified Data.ByteString as B
-import           Data.Text.Encoding
-
+import           Data.Text (Text, pack)
 import           IHaskell.IPython.Types
 
 instance ToJSON LanguageInfo where
@@ -34,6 +31,23 @@
       , "language_info" .= languageInfo rep
       ]
 
+  toJSON ExecuteRequest
+    { getCode = code
+    , getSilent = silent
+    , getStoreHistory = storeHistory
+    , getAllowStdin = allowStdin
+    , getUserVariables = userVariables
+    , getUserExpressions = userExpressions
+    } =
+    object
+      [ "code" .= code
+      , "silent" .= silent
+      , "store_history" .= storeHistory
+      , "allow_stdin" .= allowStdin
+      , "user_variables" .= userVariables
+      , "user_expressions" .= userExpressions
+      ]
+
   toJSON ExecuteReply { status = status, executionCounter = counter, pagerOutput = pager } =
     object
       [ "status" .= show status
@@ -116,6 +130,18 @@
       tuplify (HistoryReplyElement sess linum res) = (sess, linum, case res of
                                                                      Left inp         -> toJSON inp
                                                                      Right (inp, out) -> toJSON out)
+
+  toJSON req@IsCompleteReply{} =
+    object pairs
+    where
+      pairs =
+        case reviewResult req of
+          CodeComplete       -> status "complete"
+          CodeIncomplete ind -> status "incomplete" ++ indent ind
+          CodeInvalid        -> status "invalid"
+          CodeUnknown        -> status "unknown"
+      status x = ["status" .= pack x]
+      indent x = ["indent" .= pack x]
 
   toJSON body = error $ "Do not know how to convert to JSON for message " ++ show body
 
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
@@ -1,4 +1,5 @@
 {-# LANGUAGE OverloadedStrings, DeriveDataTypeable, DeriveGeneric #-}
+{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-name-shadowing -fno-warn-unused-matches #-}
 
 -- | This module contains all types used to create an IPython language kernel.
 module IHaskell.IPython.Types (
@@ -17,6 +18,7 @@
     Username(..),
     Metadata(..),
     MessageType(..),
+    CodeReview(..),
     Width(..),
     Height(..),
     StreamType(..),
@@ -34,19 +36,18 @@
     extractPlain,
     ) where
 
-import           Data.Aeson
 import           Control.Applicative ((<$>), (<*>))
+import           Data.Aeson
 import           Data.ByteString (ByteString)
+import           Data.List (find)
+import           Data.Map (Map)
+import           Data.Serialize
+import           Data.Text (Text)
 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)
 import           Data.Typeable
-import           Data.List (find)
-import           Data.Map (Map)
+import           GHC.Generics (Generic)
+import           IHaskell.IPython.Message.UUID
 
 ------------------ IPython Kernel Profile Types ----------------------
 --
@@ -169,13 +170,18 @@
 -- | The type of a message, corresponding to IPython message types.
 data MessageType = KernelInfoReplyMessage
                  | KernelInfoRequestMessage
+                 | ExecuteInputMessage
                  | ExecuteReplyMessage
+                 | ExecuteErrorMessage
                  | ExecuteRequestMessage
+                 | ExecuteResultMessage
                  | StatusMessage
                  | StreamMessage
                  | DisplayDataMessage
                  | OutputMessage
                  | InputMessage
+                 | IsCompleteRequestMessage
+                 | IsCompleteReplyMessage
                  | CompleteRequestMessage
                  | CompleteReplyMessage
                  | InspectRequestMessage
@@ -195,13 +201,18 @@
 showMessageType :: MessageType -> String
 showMessageType KernelInfoReplyMessage = "kernel_info_reply"
 showMessageType KernelInfoRequestMessage = "kernel_info_request"
+showMessageType ExecuteInputMessage = "execute_input"
 showMessageType ExecuteReplyMessage = "execute_reply"
+showMessageType ExecuteErrorMessage = "error"
 showMessageType ExecuteRequestMessage = "execute_request"
+showMessageType ExecuteResultMessage = "execute_result"
 showMessageType StatusMessage = "status"
 showMessageType StreamMessage = "stream"
 showMessageType DisplayDataMessage = "display_data"
 showMessageType OutputMessage = "pyout"
 showMessageType InputMessage = "pyin"
+showMessageType IsCompleteRequestMessage = "is_complete_request"
+showMessageType IsCompleteReplyMessage = "is_complete_reply"
 showMessageType CompleteRequestMessage = "complete_request"
 showMessageType CompleteReplyMessage = "complete_reply"
 showMessageType InspectRequestMessage = "inspect_request"
@@ -222,13 +233,18 @@
     case s of
       "kernel_info_reply"   -> return KernelInfoReplyMessage
       "kernel_info_request" -> return KernelInfoRequestMessage
+      "execute_input"       -> return ExecuteInputMessage
       "execute_reply"       -> return ExecuteReplyMessage
+      "error"               -> return ExecuteErrorMessage
       "execute_request"     -> return ExecuteRequestMessage
+      "execute_result"      -> return ExecuteResultMessage
       "status"              -> return StatusMessage
       "stream"              -> return StreamMessage
       "display_data"        -> return DisplayDataMessage
       "pyout"               -> return OutputMessage
       "pyin"                -> return InputMessage
+      "is_complete_request" -> return IsCompleteRequestMessage
+      "is_complete_reply"   -> return IsCompleteReplyMessage
       "complete_request"    -> return CompleteRequestMessage
       "complete_reply"      -> return CompleteReplyMessage
       "inspect_request"     -> return InspectRequestMessage
@@ -243,6 +259,7 @@
       "comm_close"          -> return CommCloseMessage
       "history_request"     -> return HistoryRequestMessage
       "history_reply"       -> return HistoryReplyMessage
+      "status_message"      -> return StatusMessage
 
       _                     -> fail ("Unknown message type: " ++ show s)
   parseJSON _ = fail "Must be a string."
@@ -256,6 +273,12 @@
          }
   deriving (Show, Eq)
 
+data CodeReview = CodeComplete
+                | CodeIncomplete String -- ^ String to be used to indent next line of input
+                | CodeInvalid
+                | CodeUnknown
+  deriving Show
+
 -- | A message used to communicate with the IPython frontend.
 data Message =
              -- | A request from a frontend for information about the kernel.
@@ -270,6 +293,13 @@
                  }
              |
              -- | A request from a frontend to execute some code.
+               ExecuteInput
+                 { header :: MessageHeader
+                 , getCode :: Text         -- ^ The code string.
+                 , executionCounter :: Int -- ^ The execution count, i.e. which output this is.
+                 }
+             |
+             -- | A request from a frontend to execute some code.
                ExecuteRequest
                  { header :: MessageHeader
                  , getCode :: Text              -- ^ The code string.
@@ -288,6 +318,23 @@
                  , executionCounter :: Int               -- ^ The execution count, i.e. which output this is.
                  }
              |
+             -- | A reply to an execute request.
+               ExecuteResult
+                 { header :: MessageHeader
+                 , dataResult :: [DisplayData]           -- ^ Key/value pairs (keys are MIME types)
+                 , metadataResult :: Map String String   -- ^ Any metadata that describes the data
+                 , executionCounter :: Int               -- ^ The execution count, i.e. which output this is.
+                 }
+             |
+             -- | An error reply to an execute request
+               ExecuteError
+                 { header :: MessageHeader
+                 , pagerOutput :: [DisplayData]          -- ^ The mimebundles to display in the pager.
+                 , traceback :: [Text]
+                 , ename :: Text
+                 , evalue :: Text
+                 }
+             |
                PublishStatus
                  { header :: MessageHeader
                  , executionState :: ExecutionState      -- ^ The execution state of the kernel.
@@ -316,7 +363,19 @@
                  , inCode :: String                      -- ^ Submitted input code.
                  , executionCount :: Int                 -- ^ Which input this is.
                  }
+             | Input { header :: MessageHeader, getCode :: Text, executionCount :: Int }
+             | Output { header :: MessageHeader, getText :: [DisplayData], executionCount :: Int }
              |
+               IsCompleteRequest
+                 { header :: MessageHeader
+                 , inputToReview :: String               -- ^ The code entered in the repl.
+                 }
+             |
+               IsCompleteReply
+                 { header :: MessageHeader
+                 , reviewResult :: CodeReview            -- ^ The result of reviewing the code.
+                 }
+             |
                CompleteRequest
                  { header :: MessageHeader
                  , getCode :: Text  {- ^
@@ -415,6 +474,11 @@
                         | Err
                         | Abort
 
+instance FromJSON ExecuteReplyStatus where
+  parseJSON (String "ok") = return Ok
+  parseJSON (String "error") = return Err
+  parseJSON (String "abort") = return Abort
+
 instance Show ExecuteReplyStatus where
   show Ok = "ok"
   show Err = "error"
@@ -426,15 +490,27 @@
                     | Starting
   deriving Show
 
+instance FromJSON ExecutionState where
+  parseJSON (String "busy") = return Busy
+  parseJSON (String "idle") = return Idle
+  parseJSON (String "starting") = return Starting
+
 -- | Input and output streams.
 data StreamType = Stdin
                 | Stdout
+                | Stderr
   deriving Show
 
+instance FromJSON StreamType where
+  parseJSON (String "stdin") = return Stdin
+  parseJSON (String "stdout") = return Stdout
+  parseJSON (String "stderr") = return Stderr
+
 -- | Get the reply message type for a request message type.
 replyType :: MessageType -> Maybe MessageType
 replyType KernelInfoRequestMessage = Just KernelInfoReplyMessage
 replyType ExecuteRequestMessage = Just ExecuteReplyMessage
+replyType IsCompleteRequestMessage = Just IsCompleteReplyMessage
 replyType CompleteRequestMessage = Just CompleteReplyMessage
 replyType InspectRequestMessage = Just InspectReplyMessage
 replyType ShutdownRequestMessage = Just ShutdownReplyMessage
@@ -491,3 +567,12 @@
   show MimeSvg = "image/svg+xml"
   show MimeLatex = "text/latex"
   show MimeJavascript = "application/javascript"
+
+instance Read MimeType where
+  readsPrec _ "text/plain" = [(PlainText, "")]
+  readsPrec _ "text/html" = [(MimeHtml, "")]
+  readsPrec _ "image/png" = [(MimePng 50 50, "")]
+  readsPrec _ "image/jpg" = [(MimeJpg 50 50, "")]
+  readsPrec _ "image/svg+xml" = [(MimeSvg, "")]
+  readsPrec _ "text/latex" = [(MimeLatex, "")]
+  readsPrec _ "application/javascript" = [(MimeJavascript, "")]
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
@@ -18,9 +18,9 @@
 import           Control.Exception
 import           Control.Monad
 import           Data.Aeson
-import qualified Data.ByteString.Lazy as LBS
 import           Data.ByteString (ByteString)
 import qualified Data.ByteString.Char8 as Char
+import qualified Data.ByteString.Lazy as LBS
 import           Data.Char
 import           Data.Digest.Pure.SHA as SHA
 import           Data.Monoid ((<>))
@@ -28,9 +28,9 @@
 import           System.ZMQ4 as ZMQ4 hiding (stdin)
 import           Text.Read (readMaybe)
 
-import           IHaskell.IPython.Types
 import           IHaskell.IPython.Message.Parser
-import           IHaskell.IPython.Message.Writer
+import           IHaskell.IPython.Message.Writer ()
+import           IHaskell.IPython.Types
 
 -- | The channel interface to the ZeroMQ sockets. All communication is done via Messages, which are
 -- encoded and decoded into a lower level form before being transmitted to IPython. These channels
