diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,17 @@
+# Changelog for creatur
+
+5.9.30 Automatically archive agents that trigger errors.
+       Support newer versions of binary, time.
+
+5.9.29 Report user and group when launching daemon.
+
+5.9.28 Upgraded to work with NixOS + cabal-install.
+
+5.9.27 Upgraded to lts-12.16.
+
+5.9.25 Fixed copyright year.
+
+5.9.24 Revamped to work with Stack v1.7.1.
+       Added exception handling.
+
+## Unreleased changes
diff --git a/ChangeLog.md b/ChangeLog.md
deleted file mode 100644
--- a/ChangeLog.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Changelog for creatur
-
-5.9.28 Upgraded to work with NixOS + cabal-install.
-
-5.9.27 Upgraded to lts-12.16.
-
-5.9.25 Fixed copyright year.
-
-5.9.24 Revamped to work with Stack v1.7.1.
-       Added exception handling.
-
-## Unreleased changes
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,27 +1,30 @@
-Copyright Amy de Buitléir (c) 2010-2018
+Copyright (c) 2010-2021, Amy de Buitléir
 
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
 
-* Redistributions of source code must retain the above copyright 
-  notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
-  notice, this list of conditions and the following disclaimer in the
-  documentation and/or other materials provided with the distribution.
-* Neither the name of the author nor the names of other contributors
-  may be used to endorse or promote products derived from this software
-  without specific prior written permission.
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
 
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Amy de Buitléir nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/creatur.cabal b/creatur.cabal
--- a/creatur.cabal
+++ b/creatur.cabal
@@ -1,110 +1,112 @@
-name:           creatur
-version:        5.9.28
-synopsis:       Framework for artificial life experiments.
-description:    Please see the README on GitHub at <https://github.com/mhwombat/creatur#readme>
-category:       AI
-homepage:       https://github.com/mhwombat/creatur#readme
-bug-reports:    https://github.com/mhwombat/creatur/issues
-author:         Amy de Buitléir
-maintainer:     amy@nualeargais.ie
-copyright:      2012-2019 Amy de Buitléir
-license:        BSD3
-license-file:   LICENSE
-build-type:     Simple
-cabal-version:  >= 1.10
+cabal-version:      2.4
+synopsis:           Framework for artificial life experiments.
+name:               creatur
+version:            5.9.30
+description:
+  Please see the README on GitHub at <https://github.com/mhwombat/creatur#readme>
+homepage:           https://github.com/mhwombat/creatur
+bug-reports:        https://github.com/mhwombat/creatur/issues
+license:            BSD-3-Clause
+license-file:       LICENSE
+author:             Amy de Buitléir
+maintainer:         amy@nualeargais.ie
+copyright:          2012-2021 Amy de Buitléir
+category:           AI
 extra-source-files:
-    ChangeLog.md
-    README.md
+  CHANGELOG.md
+  README.md
 
 source-repository head
-  type: git
+  type:     git
   location: https://github.com/mhwombat/creatur
 
+common common-stuff
+  default-language: Haskell2010
+
 library
+  import:          common-stuff
+  hs-source-dirs:  src
   exposed-modules:
-      ALife.Creatur
-      ALife.Creatur.Checklist
-      ALife.Creatur.Clock
-      ALife.Creatur.Counter
-      ALife.Creatur.Daemon
-      ALife.Creatur.Database
-      ALife.Creatur.Database.CachedFileSystem
-      ALife.Creatur.Database.CachedFileSystemInternal
-      ALife.Creatur.Database.FileSystem
-      ALife.Creatur.Genetics.Analysis
-      ALife.Creatur.Genetics.BRGCBool
-      ALife.Creatur.Genetics.BRGCWord16
-      ALife.Creatur.Genetics.BRGCWord8
-      ALife.Creatur.Genetics.Diploid
-      ALife.Creatur.Genetics.Recombination
-      ALife.Creatur.Genetics.Reproduction.Sexual
-      ALife.Creatur.Genetics.Reproduction.SimplifiedSexual
-      ALife.Creatur.Logger
-      ALife.Creatur.Logger.SimpleLogger
-      ALife.Creatur.Logger.SimpleRotatingLogger
-      ALife.Creatur.Namer
-      ALife.Creatur.Persistent
-      ALife.Creatur.Task
-      ALife.Creatur.Universe
-      ALife.Creatur.Util
-  other-modules:
-      Paths_creatur
-  hs-source-dirs:
-      src
+    ALife.Creatur
+    ALife.Creatur.Checklist
+    ALife.Creatur.Clock
+    ALife.Creatur.Counter
+    ALife.Creatur.Daemon
+    ALife.Creatur.Database
+    ALife.Creatur.Database.CachedFileSystem
+    ALife.Creatur.Database.CachedFileSystemInternal
+    ALife.Creatur.Database.FileSystem
+    ALife.Creatur.Genetics.Analysis
+    ALife.Creatur.Genetics.BRGCBool
+    ALife.Creatur.Genetics.BRGCWord16
+    ALife.Creatur.Genetics.BRGCWord8
+    ALife.Creatur.Genetics.Diploid
+    ALife.Creatur.Genetics.Recombination
+    ALife.Creatur.Genetics.Reproduction.Sexual
+    ALife.Creatur.Genetics.Reproduction.SimplifiedSexual
+    ALife.Creatur.Logger
+    ALife.Creatur.Logger.SimpleLogger
+    ALife.Creatur.Logger.SimpleRotatingLogger
+    ALife.Creatur.Namer
+    ALife.Creatur.Persistent
+    ALife.Creatur.Task
+    ALife.Creatur.Universe
+    ALife.Creatur.Util
+  other-modules:   Paths_creatur
+  autogen-modules: Paths_creatur
+  ghc-options:     -Wall -Wunused-packages
   build-depends:
-      MonadRandom >= 0.5.1 && < 0.6
-    , array >= 0.5.2 && < 0.6
-    , base >=4.7 && <5
-    , binary ==0.8.*
-    , bytestring >= 0.10.8 && < 0.11
-    , cereal >= 0.5.7 && < 0.6
-    , cond >= 0.4.1 && < 0.5
-    , directory >= 1.3.1 && < 1.4
-    , exceptions >= 0.10.0 && < 0.11
-    , filepath >= 1.4.2 && < 1.5
-    , gray-extended >= 1.5.4 && < 1.6
-    , hdaemonize >= 0.5.5 && < 0.6
-    , hsyslog >= 5.0.1 && < 5.1
-    , mtl >= 2.2.2 && < 2.3
-    , random >= 1.1 && < 1.2
-    , split >= 0.2.3 && < 0.3
-    , time ==1.8.*
-    , transformers >= 0.5.5 && < 0.6
-    , unix >= 2.7.2 && < 2.8
-  default-language: Haskell2010
+    , array          ^>=0.5.2
+    , base           >=4.7    && <5
+    , binary         >=0.8    && <0.11
+    , bytestring     >=0.10.8 && <0.12
+    , cereal         ^>=0.5.7
+    , cond           ^>=0.4.1
+    , directory      ^>=1.3.1
+    , exceptions     ^>=0.10.0
+    , filepath       ^>=1.4.2
+    , gray-extended  ^>=1.5.9
+    , hdaemonize     ^>=0.5.5
+    , hsyslog        ^>=5.0.1
+    , MonadRandom    ^>=0.5.1
+    , mtl            ^>=2.2.2
+    , random         >=1.1    && <1.3
+    , split          ^>=0.2.3
+    , time           >=1.1    && <1.13
+    , transformers   >=0.5.5  && <0.7
+    , unix           ^>=2.7.2
 
 test-suite creatur-test
-  type: exitcode-stdio-1.0
-  main-is: Spec.hs
+  import:         common-stuff
+  type:           exitcode-stdio-1.0
+  hs-source-dirs: test
+  main-is:        Spec.hs
   other-modules:
-      ALife.Creatur.ChecklistQC
-      ALife.Creatur.CounterQC
-      ALife.Creatur.Database.CachedFileSystemQC
-      ALife.Creatur.Database.FileSystemQC
-      ALife.Creatur.Genetics.BRGCBoolQC
-      ALife.Creatur.Genetics.BRGCWord16QC
-      ALife.Creatur.Genetics.BRGCWord8QC
-      ALife.Creatur.Genetics.DiploidQC
-      ALife.Creatur.Genetics.RecombinationQC
-      ALife.Creatur.PersistentQC
-      ALife.Creatur.UniverseQC
-      ALife.Creatur.UtilQC
-      Paths_creatur
-  hs-source-dirs:
-      test
-  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+    ALife.Creatur.ChecklistQC
+    ALife.Creatur.CounterQC
+    ALife.Creatur.Database.CachedFileSystemQC
+    ALife.Creatur.Database.FileSystemQC
+    ALife.Creatur.Genetics.BRGCBoolQC
+    ALife.Creatur.Genetics.BRGCWord16QC
+    ALife.Creatur.Genetics.BRGCWord8QC
+    ALife.Creatur.Genetics.DiploidQC
+    ALife.Creatur.Genetics.RecombinationQC
+    ALife.Creatur.PersistentQC
+    ALife.Creatur.UniverseQC
+    ALife.Creatur.UtilQC
+  ghc-options:
+    -threaded -rtsopts -with-rtsopts=-N -Wall -Wunused-packages
   build-depends:
-      HUnit
-    , MonadRandom
-    , QuickCheck
     , base
     , cereal
     , creatur
     , directory
     , filepath
+    , HUnit
+    , MonadRandom
     , mtl
+    , QuickCheck
     , temporary
     , test-framework
     , test-framework-hunit
     , test-framework-quickcheck2
-  default-language: Haskell2010
diff --git a/src/ALife/Creatur.hs b/src/ALife/Creatur.hs
--- a/src/ALife/Creatur.hs
+++ b/src/ALife/Creatur.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Checklist.hs b/src/ALife/Creatur/Checklist.hs
--- a/src/ALife/Creatur/Checklist.hs
+++ b/src/ALife/Creatur/Checklist.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Checklist
--- Copyright   :  (c) Amy de Buitléir 2013-2019
+-- Copyright   :  (c) 2013-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Clock.hs b/src/ALife/Creatur/Clock.hs
--- a/src/ALife/Creatur/Clock.hs
+++ b/src/ALife/Creatur/Clock.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Clock
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Counter.hs b/src/ALife/Creatur/Counter.hs
--- a/src/ALife/Creatur/Counter.hs
+++ b/src/ALife/Creatur/Counter.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Counter
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Daemon.hs b/src/ALife/Creatur/Daemon.hs
--- a/src/ALife/Creatur/Daemon.hs
+++ b/src/ALife/Creatur/Daemon.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Daemon
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -11,8 +11,8 @@
 -- framework.
 --
 ------------------------------------------------------------------------
-{-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TypeFamilies     #-}
 
 module ALife.Creatur.Daemon
   (
@@ -24,19 +24,22 @@
     requestShutdown
   ) where
 
-import Control.Concurrent (MVar, newMVar, readMVar, swapMVar,
-  threadDelay)
-import Control.Exception (SomeException, handle, catch)
-import Control.Monad (when)
-import Control.Monad.State (StateT, execStateT)
-import Foreign.C.String (withCStringLen)
-import System.IO (hPutStrLn, stderr)
-import System.IO.Unsafe (unsafePerformIO)
+import           Control.Concurrent
+    (MVar, newMVar, readMVar, swapMVar, threadDelay)
+import           Control.Exception      (SomeException, catch, handle)
+import           Control.Monad          (when)
+import           Control.Monad.State    (StateT, execStateT)
+import           Foreign.C.String       (withCStringLen)
+import           System.IO              (hPutStrLn, stderr)
+import           System.IO.Unsafe       (unsafePerformIO)
 import qualified System.Posix.Daemonize as D
-import System.Posix.Signals (Handler(Catch), fullSignalSet,
-  installHandler, sigTERM)
-import System.Posix.Syslog (Priority(Warning), Facility(Daemon), syslog)
-import System.Posix.User (getLoginName, getRealUserID)
+import           System.Posix.Signals
+    (Handler (Catch), fullSignalSet, installHandler, sigTERM)
+import           System.Posix.Syslog
+    (Facility (Daemon), Priority (Warning), syslog)
+import           System.Posix.User
+    (getGroupEntryForID, getLoginName, getRealGroupID, getRealUserID,
+    groupName)
 
 termReceived :: MVar Bool
 termReceived = unsafePerformIO (newMVar False)
@@ -45,21 +48,21 @@
 data Job s = Job
   {
     -- | Operations to perform on startup.
-    onStartup :: s -> IO s,
+    onStartup   :: s -> IO s,
     -- | Operations to perform on shutdown.
-    onShutdown :: s -> IO (),
+    onShutdown  :: s -> IO (),
     -- | Operations to perform if an exception occurs.
     onException :: s -> SomeException -> IO s,
     -- | Operations to perform repeatedly while running.
-    task :: StateT s IO (),
+    task        :: StateT s IO (),
     -- | Number of microseconds to sleep between invocations of @'task'@.
-    sleepTime :: Int
+    sleepTime   :: Int
   }
 
 data CreaturDaemon p s = CreaturDaemon
   {
     daemon :: D.CreateDaemon p,
-    job :: Job s
+    job    :: Job s
   }
 
 -- | Creates a simple daemon to run a job. The daemon will run under
@@ -80,7 +83,9 @@
     then putStrLn "Must run as root"
     else do
       u <- defaultToLoginName (D.user . daemon $ d)
-      g <- defaultToLoginName (D.user . daemon $ d)
+      g <- defaultToGroupName (D.user . daemon $ d)
+      putStrLn $ "Launching daemon as user " ++ show u
+                   ++ ", group " ++ show g
       let d' = (daemon d) { D.user = u, D.group = g }
       catch (D.serviced d') handleLaunchError
 
@@ -98,7 +103,14 @@
 
 defaultToLoginName :: Maybe String -> IO (Maybe String)
 defaultToLoginName (Just "") = fmap Just getLoginName
-defaultToLoginName x = return x
+defaultToLoginName x         = return x
+
+defaultToGroupName :: Maybe String -> IO (Maybe String)
+defaultToGroupName (Just "") = fmap Just getGroupName
+defaultToGroupName x         = return x
+
+getGroupName :: IO String
+getGroupName = fmap groupName $ getRealGroupID >>= getGroupEntryForID
 
 daemonMain :: Job s -> s -> () -> IO ()
 daemonMain t s _ = do
diff --git a/src/ALife/Creatur/Database.hs b/src/ALife/Creatur/Database.hs
--- a/src/ALife/Creatur/Database.hs
+++ b/src/ALife/Creatur/Database.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Database
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Database/CachedFileSystem.hs b/src/ALife/Creatur/Database/CachedFileSystem.hs
--- a/src/ALife/Creatur/Database/CachedFileSystem.hs
+++ b/src/ALife/Creatur/Database/CachedFileSystem.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Database.CachedFileSystem
--- Copyright   :  (c) Amy de Buitléir 2014-2019
+-- Copyright   :  (c) 2014-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Database/CachedFileSystemInternal.hs b/src/ALife/Creatur/Database/CachedFileSystemInternal.hs
--- a/src/ALife/Creatur/Database/CachedFileSystemInternal.hs
+++ b/src/ALife/Creatur/Database/CachedFileSystemInternal.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Database.CachedFileSystemInternal
--- Copyright   :  (c) Amy de Buitléir 2014-2019
+-- Copyright   :  (c) 2014-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Database/FileSystem.hs b/src/ALife/Creatur/Database/FileSystem.hs
--- a/src/ALife/Creatur/Database/FileSystem.hs
+++ b/src/ALife/Creatur/Database/FileSystem.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Database.FileSystem
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Genetics/Analysis.hs b/src/ALife/Creatur/Genetics/Analysis.hs
--- a/src/ALife/Creatur/Genetics/Analysis.hs
+++ b/src/ALife/Creatur/Genetics/Analysis.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.Analysis
--- Copyright   :  (c) Amy de Buitléir 2013-2019
+-- Copyright   :  (c) 2013-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Genetics/BRGCBool.hs b/src/ALife/Creatur/Genetics/BRGCBool.hs
--- a/src/ALife/Creatur/Genetics/BRGCBool.hs
+++ b/src/ALife/Creatur/Genetics/BRGCBool.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.BRGCBool
--- Copyright   :  (c) Amy de Buitléir 2013-2019
+-- Copyright   :  (c) 2013-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Genetics/BRGCWord16.hs b/src/ALife/Creatur/Genetics/BRGCWord16.hs
--- a/src/ALife/Creatur/Genetics/BRGCWord16.hs
+++ b/src/ALife/Creatur/Genetics/BRGCWord16.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.BRGCWord16
--- Copyright   :  (c) Amy de Buitléir 2014-2019
+-- Copyright   :  (c) 2014-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Genetics/BRGCWord8.hs b/src/ALife/Creatur/Genetics/BRGCWord8.hs
--- a/src/ALife/Creatur/Genetics/BRGCWord8.hs
+++ b/src/ALife/Creatur/Genetics/BRGCWord8.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.BRGCWord8
--- Copyright   :  (c) Amy de Buitléir 2013-2019
+-- Copyright   :  (c) 2013-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -165,7 +165,7 @@
                      then Right (L, "L1")
                      else Right (R, "R1")
 convertLR _ = Left "logic error"
-  
+
 -- | Sums: encode choice between constructors
 instance (GGenetic a) => GGenetic (M1 i c a) where
   gput (M1 x) = gput x
@@ -299,7 +299,7 @@
         f m y bs = f (m-1) y' (b:bs)
           where y' = y `div` 0x100
                 b = fromIntegral $ y `mod` 0x100
- 
+
 bytesToIntegral :: Integral t => [Word8] -> t
 bytesToIntegral bs = f (bs, 0)
   where f ([], n) = n
@@ -324,7 +324,7 @@
   if null mss
     then return $ Right xs
     else return $ Left (head mss)
- 
+
 -- | Write a Word8 value to the genome without encoding it
 putRawWord8 :: Word8 -> Writer ()
 putRawWord8 x = do
@@ -356,16 +356,16 @@
   (xs, msgs) <- S.get
   let msg = show (length xs) ++ ": wrote " ++ desc
   S.put (xs, msg:msgs)
-  
+
 putAndReport :: [Word8] -> String -> Writer ()
 putAndReport bytes msg = putRawWord8s bytes >> reportW msg
 
 replaceReportW :: String -> Writer ()
 replaceReportW desc = do
-  (xs, _:msgs) <- S.get
+  ~(xs, _:msgs) <- S.get
   let msg = show (length xs) ++ ": wrote " ++ desc
   S.put (xs, msg:msgs)
-  
+
 reportR :: String -> Reader ()
 reportR desc = do
   (xs, i, msgs) <- S.get
@@ -383,10 +383,10 @@
 
 replaceReportR :: String -> Reader ()
 replaceReportR desc = do
-  (xs, i, _:msgs) <- S.get
+  ~(xs, i, _:msgs) <- S.get
   let msg = show i ++ ": read " ++ desc
   S.put (xs, i, msg:msgs)
-  
+
 --
 -- Diploid genes
 --
diff --git a/src/ALife/Creatur/Genetics/Diploid.hs b/src/ALife/Creatur/Genetics/Diploid.hs
--- a/src/ALife/Creatur/Genetics/Diploid.hs
+++ b/src/ALife/Creatur/Genetics/Diploid.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.Diploid
--- Copyright   :  (c) Amy de Buitléir 2013-2019
+-- Copyright   :  (c) 2013-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Genetics/Recombination.hs b/src/ALife/Creatur/Genetics/Recombination.hs
--- a/src/ALife/Creatur/Genetics/Recombination.hs
+++ b/src/ALife/Creatur/Genetics/Recombination.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.Recombination
--- Copyright   :  (c) Amy de Buitléir 2011-2019
+-- Copyright   :  (c) 2011-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Genetics/Reproduction/Sexual.hs b/src/ALife/Creatur/Genetics/Reproduction/Sexual.hs
--- a/src/ALife/Creatur/Genetics/Reproduction/Sexual.hs
+++ b/src/ALife/Creatur/Genetics/Reproduction/Sexual.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.Reproduction.Sexual
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Genetics/Reproduction/SimplifiedSexual.hs b/src/ALife/Creatur/Genetics/Reproduction/SimplifiedSexual.hs
--- a/src/ALife/Creatur/Genetics/Reproduction/SimplifiedSexual.hs
+++ b/src/ALife/Creatur/Genetics/Reproduction/SimplifiedSexual.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.Reproduction.SimplifiedSexual
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Logger.hs b/src/ALife/Creatur/Logger.hs
--- a/src/ALife/Creatur/Logger.hs
+++ b/src/ALife/Creatur/Logger.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Logger
--- Copyright   :  (c) Amy de Buitléir 2011-2019
+-- Copyright   :  (c) 2011-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Logger/SimpleLogger.hs b/src/ALife/Creatur/Logger/SimpleLogger.hs
--- a/src/ALife/Creatur/Logger/SimpleLogger.hs
+++ b/src/ALife/Creatur/Logger/SimpleLogger.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Logger.SimpleLogger
--- Copyright   :  (c) Amy de Buitléir 2011-2019
+-- Copyright   :  (c) 2011-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Logger/SimpleRotatingLogger.hs b/src/ALife/Creatur/Logger/SimpleRotatingLogger.hs
--- a/src/ALife/Creatur/Logger/SimpleRotatingLogger.hs
+++ b/src/ALife/Creatur/Logger/SimpleRotatingLogger.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Logger.SimpleRotatingLogger
--- Copyright   :  (c) Amy de Buitléir 2011-2019
+-- Copyright   :  (c) 2011-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Namer.hs b/src/ALife/Creatur/Namer.hs
--- a/src/ALife/Creatur/Namer.hs
+++ b/src/ALife/Creatur/Namer.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Namer
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Persistent.hs b/src/ALife/Creatur/Persistent.hs
--- a/src/ALife/Creatur/Persistent.hs
+++ b/src/ALife/Creatur/Persistent.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Persistent
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Task.hs b/src/ALife/Creatur/Task.hs
--- a/src/ALife/Creatur/Task.hs
+++ b/src/ALife/Creatur/Task.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Task
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/src/ALife/Creatur/Universe.hs b/src/ALife/Creatur/Universe.hs
--- a/src/ALife/Creatur/Universe.hs
+++ b/src/ALife/Creatur/Universe.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Universe
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
@@ -10,7 +10,10 @@
 -- Provides a habitat for artificial life.
 --
 ------------------------------------------------------------------------
-{-# LANGUAGE TypeFamilies, FlexibleContexts, FlexibleInstances, ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleContexts    #-}
+{-# LANGUAGE FlexibleInstances   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies        #-}
 module ALife.Creatur.Universe
   (
     -- * Constructors
@@ -49,24 +52,28 @@
     markDone
  ) where
 
-import Prelude hiding (lookup)
+import           Prelude                                 hiding (lookup)
 
-import qualified ALife.Creatur as A
-import qualified ALife.Creatur.Namer as N
-import qualified ALife.Creatur.Checklist as CL
-import qualified ALife.Creatur.Clock as C
-import qualified ALife.Creatur.Counter as K
-import qualified ALife.Creatur.Database as D
-import qualified ALife.Creatur.Database.FileSystem as FS
+import qualified ALife.Creatur                           as A
+import qualified ALife.Creatur.Checklist                 as CL
+import qualified ALife.Creatur.Clock                     as C
+import qualified ALife.Creatur.Counter                   as K
+import qualified ALife.Creatur.Database                  as D
 import qualified ALife.Creatur.Database.CachedFileSystem as CFS
-import qualified ALife.Creatur.Logger as L
-import qualified ALife.Creatur.Logger.SimpleLogger as SL
-import ALife.Creatur.Util (stateMap, shuffle)
-import Control.Monad.IO.Class (liftIO)
-import Control.Monad.Random (evalRandIO)
-import Control.Monad.State (StateT, get)
-import Data.Either (partitionEithers)
-import Data.Serialize (Serialize)
+import qualified ALife.Creatur.Database.FileSystem       as FS
+import qualified ALife.Creatur.Logger                    as L
+import qualified ALife.Creatur.Logger.SimpleLogger       as SL
+import qualified ALife.Creatur.Namer                     as N
+import           ALife.Creatur.Util                      (shuffle, stateMap)
+import           Control.Exception                       (SomeException)
+import           Control.Monad.Catch                     (catchAll)
+import           Control.Monad.IO.Class                  (liftIO)
+import           Control.Monad.Random                    (evalRandIO)
+import           Control.Monad.State                     (StateT, get)
+import           Data.Either                             (partitionEithers)
+import           Data.Serialize                          (Serialize)
+import           GHC.Stack
+    (callStack, prettyCallStack)
 
 -- | A habitat containing artificial life.
 class (C.Clock (Clock u), L.Logger (Logger u), D.Database (AgentDB u),
@@ -233,7 +240,7 @@
     Left msg ->
       writeToLog $ "Unable to read '" ++ name ++ "': " ++ msg
     Right a ->
-      program a >>= store
+      catchAll (program a >>= store) (handleException . A.agentId $ a)
 
 -- | A program involving multiple agents.
 --   The input parameter is a list of agents.
@@ -245,8 +252,19 @@
 withAgents
   :: (Universe u, Serialize (Agent u))
     => AgentsProgram u -> [A.AgentId] -> StateT u IO ()
-withAgents program names = getAgents names >>= program >>= mapM_ store
+withAgents program names = do
+  as <- getAgents names
+  catchAll (program as >>= mapM_ store)
+      (handleException . A.agentId  . head $ as)
 
+handleException
+  :: (Universe u, Serialize (Agent u))
+    => A.AgentId -> SomeException -> StateT u IO ()
+handleException a e = do
+  writeToLog $ "WARNING: Unhandled exception: " ++ show e
+  writeToLog $ "WARNING: Call stack: " ++ prettyCallStack callStack
+  archive a
+
 -- | Returns the current lineup of (living) agents in the universe.
 --   Note: Check for @'endOfRound'@ and call @'refreshLineup'@ if needed
 --   before invoking this function.
@@ -283,10 +301,10 @@
 
 data SimpleUniverse a = SimpleUniverse
   {
-    suClock :: K.PersistentCounter,
-    suLogger :: SL.SimpleLogger,
-    suDB :: FS.FSDatabase a,
-    suNamer :: N.SimpleNamer,
+    suClock     :: K.PersistentCounter,
+    suLogger    :: SL.SimpleLogger,
+    suDB        :: FS.FSDatabase a,
+    suNamer     :: N.SimpleNamer,
     suChecklist :: CL.PersistentChecklist
   } deriving (Show, Eq)
 
@@ -319,10 +337,10 @@
 
 data CachedUniverse a = CachedUniverse
   {
-    cuClock :: K.PersistentCounter,
-    cuLogger :: SL.SimpleLogger,
-    cuDB :: CFS.CachedFSDatabase a,
-    cuNamer :: N.SimpleNamer,
+    cuClock     :: K.PersistentCounter,
+    cuLogger    :: SL.SimpleLogger,
+    cuDB        :: CFS.CachedFSDatabase a,
+    cuNamer     :: N.SimpleNamer,
     cuChecklist :: CL.PersistentChecklist
   } deriving (Show, Eq)
 
diff --git a/src/ALife/Creatur/Util.hs b/src/ALife/Creatur/Util.hs
--- a/src/ALife/Creatur/Util.hs
+++ b/src/ALife/Creatur/Util.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Util
--- Copyright   :  (c) Amy de Buitléir 2011-2019
+-- Copyright   :  (c) 2011-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/ChecklistQC.hs b/test/ALife/Creatur/ChecklistQC.hs
--- a/test/ALife/Creatur/ChecklistQC.hs
+++ b/test/ALife/Creatur/ChecklistQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.ChecklistQC
--- Copyright   :  (c) Amy de Buitléir 2013-2019
+-- Copyright   :  (c) 2013-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/CounterQC.hs b/test/ALife/Creatur/CounterQC.hs
--- a/test/ALife/Creatur/CounterQC.hs
+++ b/test/ALife/Creatur/CounterQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.CounterQC
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/Database/CachedFileSystemQC.hs b/test/ALife/Creatur/Database/CachedFileSystemQC.hs
--- a/test/ALife/Creatur/Database/CachedFileSystemQC.hs
+++ b/test/ALife/Creatur/Database/CachedFileSystemQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Database.CachedFileSystemQC
--- Copyright   :  (c) Amy de Buitléir 2014-2019
+-- Copyright   :  (c) 2014-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/Database/FileSystemQC.hs b/test/ALife/Creatur/Database/FileSystemQC.hs
--- a/test/ALife/Creatur/Database/FileSystemQC.hs
+++ b/test/ALife/Creatur/Database/FileSystemQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Database.FileSystemQC
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/Genetics/BRGCBoolQC.hs b/test/ALife/Creatur/Genetics/BRGCBoolQC.hs
--- a/test/ALife/Creatur/Genetics/BRGCBoolQC.hs
+++ b/test/ALife/Creatur/Genetics/BRGCBoolQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.BRGCBoolQC
--- Copyright   :  (c) Amy de Buitléir 2013-2019
+-- Copyright   :  (c) 2013-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/Genetics/BRGCWord16QC.hs b/test/ALife/Creatur/Genetics/BRGCWord16QC.hs
--- a/test/ALife/Creatur/Genetics/BRGCWord16QC.hs
+++ b/test/ALife/Creatur/Genetics/BRGCWord16QC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.BRGCWord16QC
--- Copyright   :  (c) Amy de Buitléir 2014-2019
+-- Copyright   :  (c) 2014-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/Genetics/BRGCWord8QC.hs b/test/ALife/Creatur/Genetics/BRGCWord8QC.hs
--- a/test/ALife/Creatur/Genetics/BRGCWord8QC.hs
+++ b/test/ALife/Creatur/Genetics/BRGCWord8QC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.BRGCWord8QC
--- Copyright   :  (c) Amy de Buitléir 2013-2019
+-- Copyright   :  (c) 2013-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/Genetics/DiploidQC.hs b/test/ALife/Creatur/Genetics/DiploidQC.hs
--- a/test/ALife/Creatur/Genetics/DiploidQC.hs
+++ b/test/ALife/Creatur/Genetics/DiploidQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.DiploidQC
--- Copyright   :  (c) Amy de Buitléir 2013-2019
+-- Copyright   :  (c) 2013-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/Genetics/RecombinationQC.hs b/test/ALife/Creatur/Genetics/RecombinationQC.hs
--- a/test/ALife/Creatur/Genetics/RecombinationQC.hs
+++ b/test/ALife/Creatur/Genetics/RecombinationQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.Genetics.RecombinationQC
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/PersistentQC.hs b/test/ALife/Creatur/PersistentQC.hs
--- a/test/ALife/Creatur/PersistentQC.hs
+++ b/test/ALife/Creatur/PersistentQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.PersistentQC
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/UniverseQC.hs b/test/ALife/Creatur/UniverseQC.hs
--- a/test/ALife/Creatur/UniverseQC.hs
+++ b/test/ALife/Creatur/UniverseQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.UniverseQC
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/ALife/Creatur/UtilQC.hs b/test/ALife/Creatur/UtilQC.hs
--- a/test/ALife/Creatur/UtilQC.hs
+++ b/test/ALife/Creatur/UtilQC.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  ALife.Creatur.UtilQC
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------
 -- |
 -- Module      :  Main
--- Copyright   :  (c) Amy de Buitléir 2012-2019
+-- Copyright   :  (c) 2012-2021 Amy de Buitléir
 -- License     :  BSD-style
 -- Maintainer  :  amy@nualeargais.ie
 -- Stability   :  experimental
