diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,13 @@
 # Revision history for reflex-ghci
 
+## 0.1.3.0
+
+* Library: Fix parsing of "Failed, n modules loaded." message
+* Library: Properly initialize when GHCi version message is the first output line
+* Executable: Terminate ghci process when ctrl-c is received
+* Library: Don't use a separate process group. Send termination signal to process, not group
+* Library: Use `watchDirectoryTree` from `Reflex.FSNotify` to avoid symlink cycles when enumerating directories
+
 ## 0.1.2.0
 
 * Extract console GHCi widgets from the executable into a library module
diff --git a/reflex-ghci.cabal b/reflex-ghci.cabal
--- a/reflex-ghci.cabal
+++ b/reflex-ghci.cabal
@@ -1,6 +1,6 @@
 cabal-version: >=1.10
 name: reflex-ghci
-version: 0.1.2.0
+version: 0.1.3.0
 synopsis: A GHCi widget library for use in reflex applications
 description:
   Run GHCi from within a reflex application and interact with it using a functional-reactive interface.
@@ -32,7 +32,7 @@
     , fsnotify >= 0.3 && < 0.4
     , process >= 1.6 && < 1.7
     , reflex >= 0.6.3 && < 0.7
-    , reflex-fsnotify >= 0.1 && < 0.2
+    , reflex-fsnotify >= 0.2 && < 0.3
     , reflex-process >= 0.1 && < 0.2
     , regex-tdfa >= 1.2.3 && < 1.3
     , reflex-vty >= 0.1.3 && < 0.2
@@ -55,7 +55,7 @@
     , reflex-process >= 0.1 && < 0.2
     , text >= 1.2 && < 1.3
     , vty >= 5.25 && < 5.26
-  ghc-options: -threaded
+  ghc-options: -threaded -rtsopts
   default-language: Haskell2010
 
 source-repository head
diff --git a/src-bin/ghci.hs b/src-bin/ghci.hs
--- a/src-bin/ghci.hs
+++ b/src-bin/ghci.hs
@@ -1,12 +1,14 @@
+import Reflex.Process
 import Reflex.Process.GHCi
 import Reflex.Vty
 import Reflex.Vty.GHCi
 
 import Control.Concurrent (threadDelay)
+import Control.Monad.IO.Class (liftIO)
 import qualified Graphics.Vty.Input as V
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as T
-import System.Process (shell)
+import System.Process (shell, terminateProcess)
 
 import Options.Applicative
 
@@ -46,7 +48,8 @@
     case expr of
       Nothing -> ghciModuleStatus g
       Just _ -> ghciPanes g
-    return $ () <$ exit
+    readyToExit <- performEvent $ ffor exit $ \_ -> liftIO $ terminateProcess $ _process_handle $ _ghci_process g
+    return $ () <$ readyToExit
 
 -- Some rudimentary test expressions
 -- Run these to test different scenarios like so:
diff --git a/src/Reflex/Process/GHCi.hs b/src/Reflex/Process/GHCi.hs
--- a/src/Reflex/Process/GHCi.hs
+++ b/src/Reflex/Process/GHCi.hs
@@ -19,7 +19,7 @@
   ) where
 
 import Reflex
-import Reflex.FSNotify (watchDirectory)
+import Reflex.FSNotify (watchDirectoryTree)
 import Reflex.Process (ProcessConfig(..), Process(..), createProcess)
 
 import Control.Monad ((<=<))
@@ -31,6 +31,7 @@
 import System.Directory (getCurrentDirectory)
 import qualified System.FSNotify as FS
 import System.FilePath.Posix (takeExtension)
+import System.Posix.Signals (sigINT)
 import qualified System.Process as P
 import qualified Text.Regex.TDFA as Regex ((=~))
 
@@ -51,10 +52,7 @@
   -> Event t ()
   -- ^ Ask GHCi to reload
   -> m (Ghci t)
-ghci p mexpr reloadReq = do
-
-  let cmd = p { P.create_group = True } -- Need to set this so that group interrupts don't impact parent
-
+ghci cmd mexpr reloadReq = do
   -- Run the process and feed it some input:
   rec proc <- createProcess cmd $ ProcessConfig
         { _processConfig_stdin = leftmost
@@ -78,7 +76,7 @@
                     else Nothing
               in attachWithMaybe f (current status) (updated status)
             ]
-        , _processConfig_signal = never
+        , _processConfig_signal = sigINT <$ requestInterrupt
         }
 
       -- Reload
@@ -94,12 +92,10 @@
      -- Only interrupt when there's a file change and we're ready and not in an idle state
       let interruptible s = s `elem` [Status_Loading, Status_Executing]
           requestInterrupt = gate (interruptible <$> current status) $ (() <$ reloadReq)
-      performEvent_ $ ffor requestInterrupt $
-        const $ liftIO $ P.interruptProcessGroupOf $ _process_handle proc
 
       -- Define some Regex patterns to use to determine GHCi's state based on output
       let okModulesLoaded = "Ok.*module.*loaded." :: ByteString
-          failedNoModulesLoaded = "Failed, no modules loaded." :: ByteString
+          failedNoModulesLoaded = "Failed,.*modules loaded." :: ByteString
           -- TODO: Is there a way to distinguish GHCi's actual exception output
           -- from someone printing "*** Exception:" to stderr?
           -- TODO: Are there other exception patterns to watch out for?
@@ -130,6 +126,9 @@
                     Nothing -> Status_LoadSucceeded
                     Just _ -> Status_Executing
                   s -> s
+
+            (lastLine:_)
+              | lastLine Regex.=~ ghciVersionMessage -> const Status_Loading
             _ -> id
         ]
 
@@ -180,19 +179,18 @@
   -- TODO: Separate the filesystem event logic into its own function
   -- Watch the project directory for changes
   pb <- getPostBuild
-  fsEvents <- watchDirectory (noDebounce FS.defaultConfig) (dir <$ pb)
-
   -- TODO Handle changes to "src" and ".cabal" differently. ":r" is only really appropriate
   -- when there are changes to loaded modules.
   -- We could use ":show modules" to see which hs files are loaded and determine what to do based
   -- on that, but we'll need to parse that output.
-  let filteredFsEvents = flip ffilter fsEvents $ \e -> 
-        takeExtension (FS.eventPath e) `elem` [".hs", ".lhs"]
 
+  fsEvents <- watchDirectoryTree (noDebounce FS.defaultConfig) (dir <$ pb) $ \e ->
+    takeExtension (FS.eventPath e) `elem` [".hs", ".lhs"]
+
   -- Events are batched because otherwise we'd get several updates corresponding to one
   -- user-level change. For example, saving a file in vim results in an event claiming
   -- the file was removed followed almost immediately by an event adding the file
-  batchedFsEvents <- batchOccurrences 0.1 filteredFsEvents
+  batchedFsEvents <- batchOccurrences 0.1 fsEvents
 
   -- Call GHCi and request a reload every time the files we're watching change
   ghci p mexec $ () <$ batchedFsEvents
