diff --git a/operational-extra.cabal b/operational-extra.cabal
--- a/operational-extra.cabal
+++ b/operational-extra.cabal
@@ -1,5 +1,5 @@
 name:                operational-extra
-version:             0.2
+version:             0.3
 synopsis:            Interpretation functions and simple instruction sets for operational
 description:         Please see README.md
 homepage:            http://github.com/andrewthad/vinyl-ecosystem
@@ -18,10 +18,13 @@
                        Control.Monad.Operational.Wait
                        Control.Monad.Operational.Exception
                        Control.Monad.Operational.Now
+                       Control.Monad.Operational.Console
   build-depends:       base >= 4.7 && < 5
                      , operational  >= 0.2.3.2
                      , time         >= 1.4
-                     , transformers >= 4.0
+                     , transformers >= 0.4.0
+                     , text
+                     , bytestring
   default-language:    Haskell2010
   default-extensions:
     RankNTypes
diff --git a/src/Control/Monad/Operational/Console.hs b/src/Control/Monad/Operational/Console.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/Operational/Console.hs
@@ -0,0 +1,47 @@
+module Control.Monad.Operational.Console where
+
+import           Control.Monad.Operational
+import           Data.Text (Text)
+import           Data.ByteString (ByteString)
+import qualified Data.Text.IO as Text
+import qualified Data.Text.Lazy as LText
+import qualified Data.Text.Lazy.IO as LText
+import qualified Data.ByteString.Char8 as ByteString
+import qualified Data.ByteString.Lazy as LByteString
+
+-- Int is the time in microseconds
+data ConsoleI content a where
+  GetI :: ConsoleI content content
+  PutI :: content -> ConsoleI content ()
+
+get :: ProgramT (ConsoleI content) m content
+get = singleton GetI
+
+put :: content -> ProgramT (ConsoleI content) m ()
+put = singleton . PutI
+
+interpretConsoleStringIO :: ConsoleI String a -> IO a
+interpretConsoleStringIO instr = case instr of
+  PutI content -> putStrLn content
+  GetI -> getLine
+
+interpretConsoleTextIO :: ConsoleI Text a -> IO a
+interpretConsoleTextIO instr = case instr of
+  PutI content -> Text.putStrLn content
+  GetI -> Text.getLine
+
+interpretConsoleLazyTextIO :: ConsoleI LText.Text a -> IO a
+interpretConsoleLazyTextIO instr = case instr of
+  PutI content -> LText.putStrLn content
+  GetI -> LText.getLine
+
+interpretConsoleByteStringIO :: ConsoleI ByteString a -> IO a
+interpretConsoleByteStringIO instr = case instr of
+  PutI content -> ByteString.putStrLn content
+  GetI -> ByteString.getLine
+
+interpretConsoleLazyByteStringIO :: ConsoleI LByteString.ByteString a -> IO a
+interpretConsoleLazyByteStringIO instr = case instr of
+  PutI content -> ByteString.putStrLn (LByteString.toStrict content)
+  GetI -> fmap LByteString.fromStrict ByteString.getLine
+
