diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,13 @@
 
 `hslua-cli` uses [PVP Versioning](https://pvp.haskell.org).
 
+## hslua-cli-1.4.0
+
+Released 2023-03-16.
+
+-   Isocline-based REPL: interactive mode is now supported with
+    the help of a new repl built with the isocline library.
+
 ## hslua-cli-1.3.0
 
 Released 2023-03-13.
diff --git a/app/hslua.hs b/app/hslua.hs
--- a/app/hslua.hs
+++ b/app/hslua.hs
@@ -26,6 +26,7 @@
               setfield registryindex "LUA_NOENV"
             openlibs
             action
+        , settingsHistory = Just ".hslua-history"
         }
   prg  <- getProgName
   args <- getArgs
diff --git a/hslua-cli.cabal b/hslua-cli.cabal
--- a/hslua-cli.cabal
+++ b/hslua-cli.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.2
 name:                hslua-cli
-version:             1.3.0
+version:             1.4.0
 synopsis:            Command-line interface for Lua
 description:         Provides an embeddable command-line interface for Lua.
                      The interface is compatible with the standard Lua
@@ -58,10 +58,13 @@
   import:              common-options
   hs-source-dirs:      src
   exposed-modules:     HsLua.CLI
-  build-depends:       base              >= 4.9.1  && < 5
+  build-depends:       base              >= 4.11   && < 5
                      , hslua-marshalling >= 2.2    && < 2.4
+                     , hslua-repl        >= 0.1    && < 0.2
                      , lua               >= 2.3    && < 2.4
                      , text              >= 1.2    && < 2.1
+  if !os(windows)
+    build-depends:     unix              >= 2.7    && < 2.9
 
 executable hslua
   import:              common-options
diff --git a/src/HsLua/CLI.hs b/src/HsLua/CLI.hs
--- a/src/HsLua/CLI.hs
+++ b/src/HsLua/CLI.hs
@@ -1,7 +1,8 @@
+{-# LANGUAGE CPP               #-}
 {-# LANGUAGE LambdaCase        #-}
 {-# LANGUAGE OverloadedStrings #-}
 {- |
-Module      : Text.Pandoc.Lua
+Module      : HsLua.CLI
 Copyright   : Copyright © 2017-2023 Albert Krewinkel
 License     : MIT
 Maintainer  : Albert Krewinkel <tarleb@hslua.org>
@@ -15,7 +16,7 @@
   , EnvBehavior (..)
   ) where
 
-import Control.Monad (unless, when, zipWithM_)
+import Control.Monad (unless, void, when, zipWithM_)
 import Data.Bifunctor (first)
 import Data.ByteString (ByteString)
 import Data.Foldable (foldl')
@@ -23,9 +24,9 @@
 import Data.Text (Text)
 import Foreign.C.String (withCString)
 import HsLua.Core (LuaE, LuaError)
+import HsLua.REPL (Config (..), defaultConfig, repl, setup)
 import System.Console.GetOpt
 import System.Environment (lookupEnv)
-import System.IO (hPutStrLn, stderr)
 import qualified Lua.Constants as Lua
 import qualified Lua.Primary as Lua
 import qualified HsLua.Core as Lua
@@ -34,6 +35,19 @@
 import qualified Data.Text.IO as T
 import qualified HsLua.Core.Utf8 as UTF8
 
+#ifndef _WINDOWS
+import System.Posix.IO (stdOutput)
+import System.Posix.Terminal (queryTerminal)
+#endif
+
+-- | Whether the program is connected to a terminal
+istty :: IO Bool
+#ifdef _WINDOWS
+istty = pure True
+#else
+istty = queryTerminal stdOutput
+#endif
+
 -- | Settings for the Lua command line interface.
 --
 -- If env vars should be ignored, and the interpreter invokes
@@ -49,9 +63,12 @@
 --
 data Settings e = Settings
   { settingsVersionInfo :: Text
+    -- ^ Additional version info to present to the user. The current
+    -- Lua version will always be printed.
   , settingsRunner      :: EnvBehavior -> LuaE e () -> IO ()
     -- ^ The Lua interpreter to be used; the first argument indicates
     -- whether environment variables should be consulted or ignored.
+  , settingsHistory     :: Maybe FilePath
   }
 
 -- | Whether environment variables should be consulted or ignored.
@@ -80,7 +97,7 @@
 showVersion :: LuaError e => Text -> LuaE e ()
 showVersion extraInfo = do
   _ <- Lua.getglobal "_VERSION"
-  versionString <- Lua.forcePeek $ Lua.peekText Lua.top
+  versionString <- Lua.forcePeek $ Lua.peekText Lua.top `Lua.lastly` Lua.pop 1
   Lua.liftIO . T.putStrLn $ versionString `T.append` extraInfo
 
 -- | Runs code given on the command line
@@ -98,6 +115,10 @@
       then Lua.setglobal g
       else Lua.throwErrorAsException
 
+--
+-- Standalone
+--
+
 -- | Uses the first command line argument as the name of a script file
 -- and tries to run that script in Lua. Falls back to stdin if no file
 -- is given. Any remaining args are passed to Lua via the global table
@@ -113,11 +134,8 @@
                   then IgnoreEnvVars
                   else ConsultEnvVars
   settingsRunner settings envVarOpt $ do
-    let putErr = Lua.liftIO . hPutStrLn stderr
     -- print version info
     when (optVersion opts) (showVersion $ settingsVersionInfo settings)
-    when (optInteractive opts) $
-      putErr "[WARNING] Flag `-i` is not supported yet."
 
     -- push `arg` table
     case optScript opts of
@@ -153,18 +171,30 @@
     mapM_ runCode (reverse $ optExecute opts)
 
     let nargs = fromIntegral . length $ optScriptArgs opts
+    let startREPL = do
+          setup defaultConfig
+            { replHistory = settingsHistory settings
+            , replInfo = replInfo defaultConfig `T.append`
+                         settingsVersionInfo settings
+            }
+          void repl
     let handleScriptResult = \case
           Lua.OK -> do
             mapM_ Lua.pushString (optScriptArgs opts)
             status <- Lua.pcallTrace nargs Lua.multret
             when (status /= Lua.OK)
               Lua.throwErrorAsException
+            when (optInteractive opts)
+              startREPL
           _      -> Lua.throwErrorAsException
+    tty <- Lua.liftIO istty
     case optScript opts of
       Just script | script /= "-" -> do
         Lua.loadfile (Just script) >>= handleScriptResult
       Nothing | optVersion opts || not (null (optExecute opts)) ->
         pure ()
+      _ | tty -> do
+        startREPL
       _ -> do
         -- load script from stdin
         Lua.loadfile Nothing >>= handleScriptResult
