diff --git a/ihaskell.cabal b/ihaskell.cabal
--- a/ihaskell.cabal
+++ b/ihaskell.cabal
@@ -7,7 +7,7 @@
 -- PVP summary:      +--+------- breaking API changes
 --                   |  | +----- non-breaking API additions
 --                   |  | | +--- code changes with no API change
-version:             0.12.0.0
+version:             0.13.0.0
 
 -- A short (one-line) description of the package.
 synopsis:            A Haskell backend kernel for the Jupyter project.
@@ -71,7 +71,7 @@
                        bytestring            ,
                        exceptions            ,
                        filepath              ,
-                       ghc                   >=8.4 && <9.11,
+                       ghc                   >=8.4 && <9.13,
                        ghc-boot              ,
                        haskeline             ,
                        parsec                ,
@@ -95,7 +95,7 @@
                        unordered-containers  -any,
                        utf8-string           -any,
                        vector                -any,
-                       ipython-kernel        >=0.11.0.0
+                       ipython-kernel        >=0.12.0.0
 
   exposed-modules: IHaskell.Display
                    IHaskell.Convert
diff --git a/main/Main.hs b/main/Main.hs
--- a/main/Main.hs
+++ b/main/Main.hs
@@ -192,7 +192,8 @@
 
     forever $ do
       -- Read the request from the request channel.
-      request <- liftIO $ readChan $ shellRequestChannel interface
+      -- when the request is completed, write the reply to `repChan`
+      (repChan, request) <- liftIO $ readChan $ shellRequestChannel interface
 
       -- Create a header for the reply.
       replyHeader <- createReplyHeader (header request)
@@ -213,7 +214,7 @@
           tempState <- handleComm replier oldState request replyHeader
           newState <- flushWidgetMessages tempState [] widgetMessageHandler
           liftIO $ putMVar state newState
-          liftIO $ writeChan (shellReplyChannel interface) SendNothing
+          liftIO $ writeChan repChan SendNothing
         else do
           -- Create the reply, possibly modifying kernel state.
           oldState <- liftIO $ takeMVar state
@@ -221,7 +222,7 @@
           liftIO $ putMVar state newState
 
           -- Write the reply to the reply channel.
-          liftIO $ writeChan (shellReplyChannel interface) reply
+          liftIO $ writeChan repChan reply
 
       -- Notify the frontend that we're done computing.
       idleHeader <- liftIO $ dupHeader replyHeader StatusMessage
diff --git a/src/IHaskell/Types.hs b/src/IHaskell/Types.hs
--- a/src/IHaskell/Types.hs
+++ b/src/IHaskell/Types.hs
@@ -47,6 +47,7 @@
 import           Data.Aeson (ToJSON (..), Value, (.=), object, Value(String))
 import           Data.Function (on)
 import           Data.Text (pack)
+import qualified Data.Text.Encoding as Text
 import           Data.Binary
 import           GHC.Generics
 
@@ -303,7 +304,12 @@
 dupHeader :: MessageHeader -> MessageType -> IO MessageHeader
 dupHeader hdr messageType = do
   uuid <- liftIO random
-  return hdr { mhMessageId = uuid, mhMsgType = messageType }
+  let sessionBytes = Text.encodeUtf8 $ pack $ uuidToString $ mhSessionId hdr
+      -- For IOPub message types, use session ID as identifier (topic)
+      newIdentifiers = if isIOPubMessageType messageType
+                       then [sessionBytes]
+                       else mhIdentifiers hdr
+  return hdr { mhMessageId = uuid, mhMsgType = messageType, mhIdentifiers = newIdentifiers }
 
 -- | Modifies a header and appends the version of the Widget Messaging Protocol as metadata
 setVersion :: MessageHeader  -- ^ The header to modify
diff --git a/src/StringUtils.hs b/src/StringUtils.hs
--- a/src/StringUtils.hs
+++ b/src/StringUtils.hs
@@ -9,15 +9,17 @@
     ) where
 
 import           IHaskellPrelude
+import           Data.Char
+import qualified Data.List as L
 import qualified Data.Text as T
 import           Data.List.Split (splitOn)
 import qualified Data.List.Split as Split
 
 lstrip :: String -> String
-lstrip = dropWhile (`elem` (" \t\r\n" :: String))
+lstrip = dropWhile isSpace
 
 rstrip :: String -> String
-rstrip = reverse . lstrip . reverse
+rstrip = L.dropWhileEnd isSpace
 
 strip :: String -> String
 strip = rstrip . lstrip
