diff --git a/quasar-wayland.cabal b/quasar-wayland.cabal
index 65f6b2abb2b69e5ae9b2a74a509ec0df07e5c724..59a9904a6436a8a1b69ee12455c4d8dd9ec3a4f9 100644
--- a/quasar-wayland.cabal
+++ b/quasar-wayland.cabal
@@ -83,19 +83,21 @@ common shared-executable-properties
 library
   import: shared-properties
   exposed-modules:
-    --Quasar.Template
+    Quasar.Wayland.Protocol
+    Quasar.Wayland.TH
   build-depends:
     base >=4.7 && <5,
     --binary,
-    --bytestring,
-    --exceptions,
+    bytestring,
+    exceptions,
     --mtl,
     --network,
-    --quasar,
-    --template-haskell,
+    quasar,
+    template-haskell,
     --unix,
     --unordered-containers,
     --stm,
+    xml,
     -- required for record-dot-preprocessor
     record-dot-preprocessor,
     record-hasfield,
diff --git a/src/Quasar/Wayland/Protocol.hs b/src/Quasar/Wayland/Protocol.hs
new file mode 100644
index 0000000000000000000000000000000000000000..24dea5725757d8cc8f7958b4ceb04c473d589ba6
--- /dev/null
+++ b/src/Quasar/Wayland/Protocol.hs
@@ -0,0 +1,29 @@
+module Quasar.Wayland.Protocol (
+  ProtocolState,
+  initialProtocolState,
+  feedInput,
+) where
+
+import Data.ByteString (ByteString)
+import Data.ByteString qualified as BS
+import Quasar.Prelude
+import Quasar.Wayland.TH
+
+$(generateWaylandProcol "protocols/wayland.xml")
+
+
+data ProtocolState = ProtocolState {
+  bytesReceived :: Word64,
+  bytesSent :: Word64
+}
+
+initialProtocolState :: ProtocolState
+initialProtocolState = ProtocolState {
+  bytesReceived = 0,
+  bytesSent = 0
+}
+
+feedInput :: ByteString -> ProtocolState -> (ProtocolState)
+feedInput bytes oldState = oldState {
+  bytesReceived = oldState.bytesReceived + fromIntegral (BS.length bytes)
+}
diff --git a/src/Quasar/Wayland/TH.hs b/src/Quasar/Wayland/TH.hs
new file mode 100644
index 0000000000000000000000000000000000000000..9d8943b7b156af51aac08b8c4d47403d336e7ba4
--- /dev/null
+++ b/src/Quasar/Wayland/TH.hs
@@ -0,0 +1,45 @@
+module Quasar.Wayland.TH (
+  generateWaylandProcol
+) where
+
+import Quasar.Prelude
+import Text.XML.Light
+import Data.ByteString qualified as BS
+
+import Language.Haskell.TH
+import Language.Haskell.TH.Lib
+import Language.Haskell.TH.Syntax (addDependentFile)
+
+
+generateWaylandProcol :: FilePath -> Q [Dec]
+generateWaylandProcol protocolFile = do
+  addDependentFile protocolFile
+  xml <- liftIO (BS.readFile protocolFile)
+  protocol <- loadProtocol xml
+
+  traceIO $ show $ (.name) <$> (interfaces protocol)
+
+  pure []
+
+
+data Protocol = Protocol {interfaces :: [Interface]}
+  deriving (Show)
+data Interface = Interface { name :: String }
+  deriving (Show)
+
+loadProtocol :: MonadFail m => BS.ByteString -> m Protocol
+loadProtocol xml = do
+  (Just protocolEl) <- pure $ parseXMLDoc xml
+  interfaces <- mapM loadInterface $ findChildren (blank_name { qName = "interface" }) protocolEl
+  pure $ Protocol interfaces
+
+loadInterface :: MonadFail m => Element -> m Interface
+loadInterface interfaceEl = do
+  name <- interfaceName
+  pure $ Interface name
+  where
+    interfaceName :: MonadFail m => m String
+    interfaceName = do
+      (Just name) <- pure $ findAttr (blank_name { qName = "name" }) interfaceEl
+      pure name
+