diff --git a/modules/client_terminal/commands.lua b/modules/client_terminal/commands.lua
index f85617fb..54985f58 100644
--- a/modules/client_terminal/commands.lua
+++ b/modules/client_terminal/commands.lua
@@ -1,6 +1,6 @@
 local function pcolored(text, color)
   color = color or 'white'
-  modules.client_terminal.addLine(text, color)
+  modules.client_terminal.addLine(tostring(text), color)
 end
 
 function draw_debug_boxes()
@@ -19,12 +19,60 @@ function live_textures_reload()
   g_textures.liveReload()
 end
 
-function auto_reload_module(name)
-  local function reloadEvent()
-    reloadModule(name)
-    scheduleEvent(reloadEvent, 1000)
+function live_module_reload(name)
+  if not name then
+    pcolored('ERROR: missing module name', 'red')
+    return
   end
-  reloadEvent()
+
+  local module = g_modules.getModule(name)
+  if not module then
+    pcolored('ERROR: unable to find module ' .. name, 'red')
+    return
+  end
+
+  if not module:isReloadble() then
+    pcolored('ERROR: that module is not reloadable', 'red')
+    return
+  end
+
+  if not module:canReload() then
+    pcolored('ERROR: some other modules requires this module, cannot reload now', 'red')
+    return
+  end
+
+  local files = {}
+  local hasFile = false
+  for _,file in pairs(g_resources.listDirectoryFiles('/' .. name)) do
+    local filepath = '/' .. name .. '/' .. file
+    local time = g_resources.getFileTime(filepath)
+    if time > 0 then
+      files[filepath] = time
+      hasFile = true
+    end
+  end
+
+  if not hasFile then
+    pcolored('ERROR: unable to find any file for module', 'red')
+    return
+  end
+
+  cycleEvent(function()
+    for filepath,time in pairs(files) do
+      local newtime = g_resources.getFileTime(filepath)
+      if newtime > time then
+        pcolored('Reloading ' .. name, 'green')
+        modules.client_terminal.flushLines()
+        module:reload()
+        files[filepath] = newtime
+
+        if name == 'client_terminal' then
+          modules.client_terminal.show()
+        end
+        break
+      end
+    end
+  end, 1000)
 end
 
 local pinging = false
diff --git a/modules/client_terminal/terminal.lua b/modules/client_terminal/terminal.lua
index 62a6878b..4867f7ba 100644
--- a/modules/client_terminal/terminal.lua
+++ b/modules/client_terminal/terminal.lua
@@ -8,7 +8,7 @@ local MaxHistory = 1000
 
 local oldenv = getfenv(0)
 setfenv(0, _G)
-commandEnv = runinsandbox('commands')
+_G.commandEnv = runinsandbox('commands')
 setfenv(0, oldenv)
 
 -- private variables
@@ -26,6 +26,7 @@ local firstShown = false
 local flushEvent
 local cachedLines = {}
 local disabled = false
+local allLines = {}
 
 -- private functions
 local function navigateCommand(step)
@@ -147,7 +148,14 @@ function init()
   terminalBuffer.onScrollChange = function(self, value) terminalSelectText:setTextVirtualOffset(value) end
 
   g_logger.setOnLog(onLog)
-  g_logger.fireOldMessages()
+
+  if not g_app.isRunning() then
+    g_logger.fireOldMessages()
+  elseif _G.terminalLines then
+    for _,line in pairs(_G.terminalLines) do
+      addLine(line.text, line.color)
+    end
+  end
 end
 
 function terminate()
@@ -171,6 +179,7 @@ function terminate()
   terminalWindow:destroy()
   terminalButton:destroy()
   commandEnv = nil
+  _G.terminalLines = allLines
 end
 
 function hideButton()
@@ -250,6 +259,7 @@ function flushLines()
     if numLines > MaxLogLines then
       local len = #terminalBuffer:getChildByIndex(1):getText()
       terminalBuffer:getChildByIndex(1):destroy()
+      table.remove(allLines, 1)
       fulltext = string.sub(fulltext, len)
     end
 
@@ -258,12 +268,15 @@ function flushLines()
     label:setText(line.text)
     label:setColor(line.color)
 
+    table.insert(allLines, {text=line.text,color=line.color})
+
     fulltext = fulltext .. '\n' .. line.text
   end
 
   terminalSelectText:setText(fulltext)
 
   cachedLines = {}
+  removeEvent(flushEvent)
   flushEvent = nil
 end
 
@@ -306,7 +319,7 @@ function executeCommand(command)
   if not func then
     local command_name = command:match('^([%w_]+)[%s]*.*')
     if command_name then
-      local args = string.split(command:match('^[%w]+[%s]*(.*)'), ' ')
+      local args = string.split(command:match('^[%w_]+[%s]*(.*)'), ' ')
       if commandEnv[command_name] and type(commandEnv[command_name]) == 'function' then
         func = function() modules.client_terminal.commandEnv[command_name](unpack(args)) end
       elseif command_name == command then
@@ -329,7 +342,7 @@ function executeCommand(command)
   local ok, ret = pcall(func)
   if ok then
     -- if the command returned a value, print it
-    if ret then print(ret) end
+    if ret then addLine(ret, 'white') end
   else
     addLine('ERROR: command failed: ' .. ret, 'red')
   end
@@ -338,4 +351,6 @@ end
 function clear()
   terminalBuffer:destroyChildren()
   terminalSelectText:setText('')
+  cachedLines = {}
+  allLines = {}
 end