diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,18 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
 
+## 0.3.5 - 2022-12-29
+
+### Fixed
+
+ - Explain what to do when git's upstream HEAD is missing.
+
+ - Explicitly initialize nix on startup. This will prevent rare but obscure errors.
+
+### Changed
+
+ - Unwrap some error messages for readability.
+
 ## 0.3.4 - 2022-12-02
 
 ### Added
diff --git a/hercules-ci-cli.cabal b/hercules-ci-cli.cabal
--- a/hercules-ci-cli.cabal
+++ b/hercules-ci-cli.cabal
@@ -1,7 +1,7 @@
 cabal-version: 1.12
 
 name:           hercules-ci-cli
-version:        0.3.4
+version:        0.3.5
 synopsis:       The hci command for working with Hercules CI
 homepage:       https://docs.hercules-ci.com
 bug-reports:    https://github.com/hercules-ci/hercules-ci-agent/issues
@@ -64,6 +64,7 @@
     , http-client-tls
     , http-types
     , katip
+    , inline-c-cpp
     , lens
     , lens-aeson
     , lifted-base
diff --git a/src/Hercules/CLI/Client.hs b/src/Hercules/CLI/Client.hs
--- a/src/Hercules/CLI/Client.hs
+++ b/src/Hercules/CLI/Client.hs
@@ -20,7 +20,6 @@
 import Protolude
 import RIO (RIO)
 import Servant.API
-import Servant.API.Generic
 import Servant.Auth.Client (Token)
 import qualified Servant.Client
 import Servant.Client.Core (ClientError, ResponseF)
diff --git a/src/Hercules/CLI/Effect.hs b/src/Hercules/CLI/Effect.hs
--- a/src/Hercules/CLI/Effect.hs
+++ b/src/Hercules/CLI/Effect.hs
@@ -63,12 +63,12 @@
           case projectOptionMaybe of
             Just x
               | not requireToken ->
-                pure
-                  ProjectData
-                    { pdProjectPath = Just x,
-                      pdProjectId = Nothing,
-                      pdToken = Nothing
-                    }
+                  pure
+                    ProjectData
+                      { pdProjectPath = Just x,
+                        pdProjectId = Nothing,
+                        pdToken = Nothing
+                      }
             _ -> getProjectEffectData projectOptionMaybe requireToken
     withAsync getProjectInfo \projectPathAsync -> do
       withNix \store evalState -> do
diff --git a/src/Hercules/CLI/Git.hs b/src/Hercules/CLI/Git.hs
--- a/src/Hercules/CLI/Git.hs
+++ b/src/Hercules/CLI/Git.hs
@@ -39,7 +39,8 @@
 getRevsAndRefs =
   -- restrict to heads and tags, because other ones aren't relevant on CI, probably
   readProcess "git" ["show-ref"] mempty <&> \x ->
-    x & toS
+    x
+      & toS
       & T.lines
       & map \ln ->
         ln
@@ -106,7 +107,13 @@
       do
         upstream <- getBranchUpstream
         upstreamRef <- readProcessString "git" ["rev-parse", "--symbolic-full-name", "@{u}"] mempty
-        upstreamDefaultRef <- readProcessString "git" ["rev-parse", "--symbolic-full-name", toS upstream <> "/HEAD"] mempty
+        upstreamDefaultRef <-
+          readProcessString "git" ["rev-parse", "--symbolic-full-name", toS upstream <> "/HEAD"] mempty
+            `onException` do
+              putErrText "hci: Could not determine remote default branch"
+              putErrText "     This may happen when the repository was initialized with git init instead of git clone"
+              putErrText "     It can usually be fixed by running:"
+              putErrText "         git remote set-head origin -a"
         pure (upstreamRef == upstreamDefaultRef)
         `onException` putErrText "hci: could not determine whether branch matches default branch"
     Left (_ :: SomeException) -> do
diff --git a/src/Hercules/CLI/Main.hs b/src/Hercules/CLI/Main.hs
--- a/src/Hercules/CLI/Main.hs
+++ b/src/Hercules/CLI/Main.hs
@@ -13,8 +13,11 @@
 import Hercules.CLI.Options (execParser, helper, mkCommand, subparser)
 import qualified Hercules.CLI.Secret as Secret
 import qualified Hercules.CLI.State as State
+import qualified Hercules.CNix
 import qualified Hercules.CNix.Exception
+import qualified Hercules.CNix.Util
 import Hercules.CNix.Verbosity (setShowTrace)
+import qualified Language.C.Inline.Cpp.Exception as C
 import qualified Options.Applicative as Optparse
 import Protolude
 
@@ -25,15 +28,35 @@
       prettyPrintHttpErrors $ do
         join $ execParser opts
 
+initNix :: IO ()
+initNix = do
+  Hercules.CNix.init
+  Hercules.CNix.Util.installDefaultSigINTHandler
+
+addNix :: Functor f => f (IO a) -> f (IO a)
+addNix = fmap (initNix *>)
+
 prettyPrintErrors :: IO a -> IO a
-prettyPrintErrors = handleHaskell . Hercules.CNix.Exception.handleExceptions
+prettyPrintErrors = handleFinal . handleFatal . handleRemainingCpp . Hercules.CNix.Exception.handleExceptions
   where
-    handleHaskell = handle \e ->
+    handleFinal = handle \e ->
       case fromException e :: Maybe ExitCode of
         Just _ -> throwIO e
         Nothing -> do
           putErrLn $ "hci: " <> displayException e
           exitFailure
+    handleFatal = handle \e -> do
+      putErrLn $ "hci: Unexpected exception: " <> fatalErrorMessage e
+      exitFailure
+    handleRemainingCpp = handle \case
+      C.CppStdException _ptr msg mt -> do
+        putErrLn $ "hci: Unexpected C++ exception: " <> msg <> foldMap (" of type" <>) mt
+        exitFailure
+      C.CppHaskellException actual -> do
+        prettyPrintErrors (throwIO actual)
+      C.CppNonStdException _ptr t -> do
+        putErrText $ "hci: Unexpected C++ exception of type " <> show t
+        exitFailure
 
 opts :: Optparse.ParserInfo (IO ())
 opts =
@@ -61,7 +84,7 @@
           <> mkCommand
             "effect"
             (Optparse.progDesc "Run effects locally")
-            Effect.commandParser
+            (addNix Effect.commandParser)
           <> mkCommand
             "secret"
             (Optparse.progDesc "Manipulate locally stored secrets")
diff --git a/src/Hercules/CLI/Nix.hs b/src/Hercules/CLI/Nix.hs
--- a/src/Hercules/CLI/Nix.hs
+++ b/src/Hercules/CLI/Nix.hs
@@ -135,7 +135,8 @@
                           [singleMatch] -> do
                             ma <- getAttr evalState attrset (encodeUtf8 singleMatch)
                             matchIsDeriv <-
-                              ma & traverse (isDerivation evalState)
+                              ma
+                                & traverse (isDerivation evalState)
                                 <&> fromMaybe False
                             if matchIsDeriv
                               then
