diff --git a/lib/Ribosome/Config/Setting.hs b/lib/Ribosome/Config/Setting.hs
--- a/lib/Ribosome/Config/Setting.hs
+++ b/lib/Ribosome/Config/Setting.hs
@@ -6,13 +6,41 @@
   settingVariableName,
   settingOr,
   settingMaybe,
+  settingR,
+  SettingError(..),
+  updateSettingR,
 ) where
 
 import Data.Either (fromRight)
+import Data.Text.Prettyprint.Doc (Doc)
+import Data.Text.Prettyprint.Doc.Render.Terminal (AnsiStyle)
 import Neovim
+import System.Log (Priority(NOTICE))
+
+import Ribosome.Control.Monad.RiboE (RiboE, liftRibo, riboE, mapE)
 import Ribosome.Control.Ribo (Ribo)
 import qualified Ribosome.Control.Ribosome as R (name)
+import Ribosome.Data.ErrorReport (ErrorReport(..))
+import Ribosome.Error.Report (ReportError(..))
+import Ribosome.Msgpack.Decode (MsgpackDecode(fromMsgpack))
+import Ribosome.Msgpack.Encode (MsgpackEncode(toMsgpack))
 
+data SettingError =
+  Other String String
+  |
+  Decode String (Doc AnsiStyle)
+  |
+  Unset String
+  deriving Show
+
+instance ReportError SettingError where
+  errorReport (Other name message) =
+    ErrorReport ("weird setting: " ++ name) ["failed to read setting `" ++ name ++ "`", message] NOTICE
+  errorReport (Decode name message) =
+    ErrorReport ("invalid setting: " ++ name) ["failed to decode setting `" ++ name ++ "`", show message] NOTICE
+  errorReport (Unset name) =
+    ErrorReport ("required setting unset: " ++ name) ["unset setting: `" ++ name ++ "`"] NOTICE
+
 data Setting a =
   Setting {
     name :: String,
@@ -56,3 +84,18 @@
   varName <- settingVariableName s
   _ <- vim_set_var' varName (toObject a)
   return ()
+
+settingR :: MsgpackDecode a => Setting a -> RiboE s SettingError a
+settingR s@(Setting n _ fallback') = do
+  varName <- liftRibo $ settingVariableName s
+  raw <- liftRibo $ vim_get_var varName
+  case raw of
+    Right o -> mapE (Decode n) $ riboE $ pure $ fromMsgpack o
+    Left _ -> riboE $ return $ case fallback' of
+      Just fb -> Right fb
+      Nothing -> Left $ Unset n
+
+updateSettingR :: MsgpackEncode a => Setting a -> a -> Ribo e ()
+updateSettingR s a = do
+  varName <- settingVariableName s
+  void $ vim_set_var' varName (toMsgpack a)
diff --git a/lib/Ribosome/Control/Lock.hs b/lib/Ribosome/Control/Lock.hs
new file mode 100644
--- /dev/null
+++ b/lib/Ribosome/Control/Lock.hs
@@ -0,0 +1,48 @@
+module Ribosome.Control.Lock(
+  getOrCreateLock,
+  lockOrSkip,
+) where
+
+import qualified Control.Lens as Lens (view, over, at)
+import qualified Data.Map.Strict as Map (insert)
+import Neovim (ask)
+import UnliftIO (finally)
+import UnliftIO.STM (TMVar, atomically, newTMVarIO, tryTakeTMVar, tryPutTMVar, modifyTVar)
+
+import Ribosome.Control.Ribo (Ribo, riboInternal)
+import Ribosome.Control.Ribosome (Ribosome(Ribosome), Locks)
+import qualified Ribosome.Control.Ribosome as Ribosome (_locks, locks)
+import qualified Ribosome.Log as Log (debugR)
+
+getLocks :: Ribo e Locks
+getLocks =
+  Ribosome.locks <$> riboInternal
+
+inspectLocks :: (Locks -> a) -> Ribo e a
+inspectLocks f = fmap f getLocks
+
+modifyLocks :: (Locks -> Locks) -> Ribo e ()
+modifyLocks f = do
+  Ribosome _ intTv _ <- ask
+  atomically $ modifyTVar intTv $ Lens.over Ribosome._locks f
+
+getOrCreateLock :: String -> Ribo e (TMVar ())
+getOrCreateLock key = do
+  currentLock <- inspectLocks $ Lens.view $ Lens.at key
+  case currentLock of
+    Just tv -> return tv
+    Nothing -> do
+      tv <- newTMVarIO ()
+      modifyLocks $ Map.insert key tv
+      getOrCreateLock key
+
+lockOrSkip :: String -> Ribo e () -> Ribo e ()
+lockOrSkip key thunk = do
+  currentLock <- getOrCreateLock key
+  currentState <- atomically $ tryTakeTMVar currentLock
+  case currentState of
+    Just _ -> do
+      Log.debugR $ "locking MVar `" ++ key ++ "`"
+      finally thunk $ atomically $ tryPutTMVar currentLock ()
+      Log.debugR $ "unlocking MVar `" ++ key ++ "`"
+    Nothing -> return ()
diff --git a/lib/Ribosome/Control/Ribo.hs b/lib/Ribosome/Control/Ribo.hs
--- a/lib/Ribosome/Control/Ribo.hs
+++ b/lib/Ribosome/Control/Ribo.hs
@@ -6,7 +6,6 @@
   inspect,
   modify,
   name,
-  lockOrSkip,
   prepend,
   modifyL,
   riboInternal,
@@ -17,15 +16,13 @@
 
 import Control.Concurrent.STM.TVar (modifyTVar, swapTVar)
 import Control.Lens (Lens')
-import qualified Control.Lens as Lens (view, over, at)
+import qualified Control.Lens as Lens (over)
 import Data.Functor (void)
-import qualified Data.Map.Strict as Map (insert)
 import Neovim (Neovim, ask)
-import UnliftIO (finally)
-import UnliftIO.STM (TVar, TMVar, atomically, readTVarIO, newTMVarIO, tryTakeTMVar, tryPutTMVar)
+import UnliftIO.STM (TVar, atomically, readTVarIO)
 
-import Ribosome.Control.Ribosome (Ribosome(Ribosome), Locks, RibosomeInternal)
-import qualified Ribosome.Control.Ribosome as Ribosome (_locks, locks, errors, _errors)
+import Ribosome.Control.Ribosome (Ribosome(Ribosome), RibosomeInternal)
+import qualified Ribosome.Control.Ribosome as Ribosome (errors, _errors)
 import Ribosome.Data.Errors (Errors)
 
 type Ribo e = Neovim (Ribosome e)
@@ -69,18 +66,6 @@
   Ribosome _ intTv _ <- ask
   readTVarIO intTv
 
-getLocks :: Ribo e Locks
-getLocks =
-  Ribosome.locks <$> riboInternal
-
-inspectLocks :: (Locks -> a) -> Ribo e a
-inspectLocks f = fmap f getLocks
-
-modifyLocks :: (Locks -> Locks) -> Ribo e ()
-modifyLocks f = do
-  Ribosome _ intTv _ <- ask
-  atomically $ modifyTVar intTv $ Lens.over Ribosome._locks f
-
 getErrors :: Ribo e Errors
 getErrors =
   Ribosome.errors <$> riboInternal
@@ -92,21 +77,3 @@
 modifyErrors f = do
   Ribosome _ intTv _ <- ask
   atomically $ modifyTVar intTv $ Lens.over Ribosome._errors f
-
-getOrCreateLock :: String -> Ribo e (TMVar ())
-getOrCreateLock key = do
-  currentLock <- inspectLocks $ Lens.view $ Lens.at key
-  case currentLock of
-    Just tv -> return tv
-    Nothing -> do
-      tv <- newTMVarIO ()
-      modifyLocks $ Map.insert key tv
-      getOrCreateLock key
-
-lockOrSkip :: String -> Ribo e () -> Ribo e ()
-lockOrSkip key thunk = do
-  currentLock <- getOrCreateLock key
-  currentState <- atomically $ tryTakeTMVar currentLock
-  case currentState of
-    Just _ -> finally thunk $ atomically $ tryPutTMVar currentLock ()
-    Nothing -> return ()
diff --git a/lib/Ribosome/Log.hs b/lib/Ribosome/Log.hs
--- a/lib/Ribosome/Log.hs
+++ b/lib/Ribosome/Log.hs
@@ -4,11 +4,16 @@
   err,
   p,
   prefixed,
+  debugR,
 ) where
 
 import Control.Monad.IO.Class (MonadIO, liftIO)
+import Neovim (ask)
 import Neovim.Log (debugM, infoM, errorM)
 
+import Ribosome.Control.Ribo (Ribo)
+import qualified Ribosome.Control.Ribosome as R (name)
+
 debug :: (MonadIO m, Show a) => String -> a -> m ()
 debug name message = liftIO $ debugM name $ show message
 
@@ -23,3 +28,8 @@
 
 prefixed :: (MonadIO m, Show a) => String -> a -> m ()
 prefixed prefix a = liftIO $ putStrLn $ prefix ++ ": " ++ show a
+
+debugR :: String -> Ribo e ()
+debugR a = do
+  pluginName <- R.name <$> ask
+  liftIO $ debugM pluginName a
diff --git a/lib/Ribosome/Msgpack/Decode.hs b/lib/Ribosome/Msgpack/Decode.hs
--- a/lib/Ribosome/Msgpack/Decode.hs
+++ b/lib/Ribosome/Msgpack/Decode.hs
@@ -1,10 +1,13 @@
-{-# LANGUAGE DefaultSignatures #-}
 {-# LANGUAGE TypeOperators #-}
 
 module Ribosome.Msgpack.Decode(
   MsgpackDecode(..),
 ) where
 
+import Data.ByteString.Internal (unpackChars)
+import Data.Map.Strict (Map, (!?))
+import qualified Data.Map.Strict as Map (fromList, toList)
+import Data.MessagePack (Object(..))
 import GHC.Generics (
   Generic,
   Rep,
@@ -20,10 +23,6 @@
   to,
   conIsRecord,
   )
-import Data.ByteString.Internal (unpackChars)
-import Data.Map.Strict (Map, (!?))
-import qualified Data.Map.Strict as Map (fromList, toList)
-import Data.MessagePack (Object(..))
 import Ribosome.Msgpack.Util (Err)
 import qualified Ribosome.Msgpack.Util as Util (string, invalid, missingRecordKey, illegalType)
 
@@ -32,15 +31,22 @@
   default fromMsgpack :: (Generic a, GMsgpackDecode (Rep a)) => Object -> Either Err a
   fromMsgpack = fmap to . gMsgpackDecode
 
+  missingKey :: String -> Object -> Either Err a
+  missingKey = Util.missingRecordKey
+
 class GMsgpackDecode f where
   gMsgpackDecode :: Object -> Either Err (f a)
 
+  gMissingKey :: String -> Object -> Either Err (f a)
+  gMissingKey = Util.missingRecordKey
+
 class MsgpackDecodeProd f where
   msgpackDecodeRecord :: Map Object Object -> Either Err (f a)
   msgpackDecodeProd :: [Object] -> Either Err ([Object], f a)
 
-instance GMsgpackDecode f => GMsgpackDecode (D1 c f) where
-  gMsgpackDecode = fmap M1 . gMsgpackDecode @f
+instance (GMsgpackDecode f) => GMsgpackDecode (D1 c f) where
+  gMsgpackDecode =
+    fmap M1 . gMsgpackDecode @f
 
 instance (Constructor c, MsgpackDecodeProd f) => GMsgpackDecode (C1 c f) where
   gMsgpackDecode =
@@ -49,16 +55,15 @@
       isRec = conIsRecord (undefined :: t c f p)
       decode o@(ObjectMap om) =
         if isRec then msgpackDecodeRecord om else Util.invalid "illegal ObjectMap for product" o
-      decode o@(ObjectArray oa) =
-        if isRec then Util.invalid "illegal ObjectArray for record" o else decode'
-        where
-          decode' = do
-            (rest, a) <- msgpackDecodeProd oa
-            case rest of
-              [] -> Right a
-              _ -> Util.invalid "too many values for product" o
+      decode o | isRec =
+        Util.invalid "illegal non-ObjectMap for record" o
       decode o =
-        Util.invalid "illegal Object for constructor" o
+        msgpackDecodeProd (prod o) >>= check
+        where
+          check ([], a) = Right a
+          check _ = Util.invalid "too many values for product" o
+          prod (ObjectArray oa) = oa
+          prod ob = [ob]
 
 instance (MsgpackDecodeProd f, MsgpackDecodeProd g) => MsgpackDecodeProd (f :*: g) where
   msgpackDecodeRecord o = do
@@ -72,17 +77,20 @@
 
 instance (Selector s, GMsgpackDecode f) => MsgpackDecodeProd (S1 s f) where
   msgpackDecodeRecord o =
-    maybe (Util.missingRecordKey key (ObjectMap o)) (fmap M1 . gMsgpackDecode) (o !? Util.string key)
+    M1 <$> maybe (gMissingKey key (ObjectMap o)) gMsgpackDecode (o !? Util.string key)
     where
       key = selName (undefined :: t s f p)
   msgpackDecodeProd (cur:rest) = do
     a <- gMsgpackDecode cur
-    return $ (rest, M1 a)
+    return (rest, M1 a)
   msgpackDecodeProd [] = Util.invalid "too few values for product" ObjectNil
 
 instance MsgpackDecode a => GMsgpackDecode (K1 i a) where
   gMsgpackDecode = fmap K1 . fromMsgpack
 
+  gMissingKey key =
+    fmap K1 . missingKey key
+
 instance (Ord k, MsgpackDecode k, MsgpackDecode v) => MsgpackDecode (Map k v) where
   fromMsgpack (ObjectMap om) = do
     m <- traverse decodePair $ Map.toList om
@@ -105,3 +113,13 @@
 instance {-# OVERLAPPABLE #-} MsgpackDecode a => MsgpackDecode [a] where
   fromMsgpack (ObjectArray oa) = traverse fromMsgpack oa
   fromMsgpack o = Util.illegalType "List" o
+
+instance MsgpackDecode a => MsgpackDecode (Maybe a) where
+  fromMsgpack ObjectNil = Right Nothing
+  fromMsgpack o = Just <$> fromMsgpack o
+
+  missingKey _ _ = Right Nothing
+
+instance MsgpackDecode Bool where
+  fromMsgpack (ObjectBool a) = Right a
+  fromMsgpack o = Util.illegalType "Bool" o
diff --git a/lib/Ribosome/Msgpack/Encode.hs b/lib/Ribosome/Msgpack/Encode.hs
--- a/lib/Ribosome/Msgpack/Encode.hs
+++ b/lib/Ribosome/Msgpack/Encode.hs
@@ -5,6 +5,10 @@
   MsgpackEncode(..),
 ) where
 
+import Data.Bifunctor (bimap)
+import Data.Map.Strict (Map)
+import qualified Data.Map.Strict as Map (fromList, toList)
+import Data.MessagePack (Object(..))
 import GHC.Generics (
   Generic,
   Rep,
@@ -20,10 +24,6 @@
   from,
   conIsRecord,
   )
-import Data.Bifunctor (bimap)
-import Data.Map.Strict (Map)
-import qualified Data.Map.Strict as Map (fromList, toList)
-import Data.MessagePack (Object(..))
 import qualified Ribosome.Msgpack.Util as Util (string, assembleMap)
 
 class MsgpackEncode a where
@@ -41,11 +41,18 @@
 instance GMsgpackEncode f => GMsgpackEncode (D1 c f) where
   gMsgpackEncode = gMsgpackEncode . unM1
 
+prodOrNewtype :: MsgpackEncodeProd f => f a -> Object
+prodOrNewtype =
+  wrap . msgpackEncodeProd
+  where
+    wrap [a] = a
+    wrap as = ObjectArray as
+
 instance (Constructor c, MsgpackEncodeProd f) => GMsgpackEncode (C1 c f) where
   gMsgpackEncode c =
     f $ unM1 c
     where
-      f = if conIsRecord c then Util.assembleMap . msgpackEncodeRecord else ObjectArray . msgpackEncodeProd
+      f = if conIsRecord c then Util.assembleMap . msgpackEncodeRecord else prodOrNewtype
 
 instance (MsgpackEncodeProd f, MsgpackEncodeProd g) => MsgpackEncodeProd (f :*: g) where
   msgpackEncodeRecord (f :*: g) = msgpackEncodeRecord f ++ msgpackEncodeRecord g
@@ -69,3 +76,9 @@
 
 instance {-# OVERLAPPABLE #-} MsgpackEncode a => MsgpackEncode [a] where
   toMsgpack = ObjectArray . fmap toMsgpack
+
+instance MsgpackEncode a => MsgpackEncode (Maybe a) where
+  toMsgpack = maybe ObjectNil toMsgpack
+
+instance MsgpackEncode Bool where
+  toMsgpack = ObjectBool
diff --git a/lib/Ribosome/Test/Exists.hs b/lib/Ribosome/Test/Exists.hs
--- a/lib/Ribosome/Test/Exists.hs
+++ b/lib/Ribosome/Test/Exists.hs
@@ -2,7 +2,7 @@
   waitForPlugin,
 ) where
 
-import Control.Monad.IO.Class
+import Control.Monad.IO.Class (MonadIO)
 import Data.Char (toUpper)
 import Neovim
 
diff --git a/ribosome.cabal b/ribosome.cabal
--- a/ribosome.cabal
+++ b/ribosome.cabal
@@ -1,6 +1,6 @@
 cabal-version: 1.12
 name: ribosome
-version: 0.2.1.0
+version: 0.2.2.0
 license: MIT
 license-file: LICENSE
 copyright: 2019 Torsten Schmits
@@ -31,6 +31,7 @@
         Ribosome.Api.Window
         Ribosome.Config.Setting
         Ribosome.Config.Settings
+        Ribosome.Control.Lock
         Ribosome.Control.Monad.Ribo
         Ribosome.Control.Monad.RiboE
         Ribosome.Control.Monad.State
diff --git a/test/u/MsgpackSpec.hs b/test/u/MsgpackSpec.hs
--- a/test/u/MsgpackSpec.hs
+++ b/test/u/MsgpackSpec.hs
@@ -1,25 +1,35 @@
 {-# OPTIONS_GHC -F -pgmF htfpp #-}
 {-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
 
 module MsgpackSpec(
   htf_thisModulesTests
 ) where
 
-import GHC.Generics (Generic)
 import Data.Either.Combinators (mapLeft)
 import Data.Int (Int64)
 import Data.Map.Strict (Map)
 import qualified Data.Map.Strict as Map (fromList)
 import Data.MessagePack (Object(..))
+import Data.Text (Text)
+import Data.Text.Prettyprint.Doc (Doc, layoutPretty, defaultLayoutOptions)
+import Data.Text.Prettyprint.Doc.Render.Terminal (renderStrict, AnsiStyle)
+import GHC.Generics (Generic)
 import Test.Framework
-import Ribosome.Msgpack.Encode (MsgpackEncode(..))
+
 import Ribosome.Msgpack.Decode (MsgpackDecode(..))
+import Ribosome.Msgpack.Encode (MsgpackEncode(..))
 import qualified Ribosome.Msgpack.Util as Util (string)
 
+newtype NT =
+  NT String
+  deriving (Eq, Show, Generic, MsgpackEncode, MsgpackDecode)
+
 data Blob =
   Blob {
     key4 :: [[Int]],
-    key5 :: Map Int String
+    key5 :: Map Int String,
+    key6 :: NT
   }
   deriving (Eq, Show, Generic, MsgpackEncode, MsgpackDecode)
 
@@ -30,13 +40,13 @@
 data Dat =
   Dat {
     key1 :: Blob,
-    key2 :: Int,
-    key3 :: Prod
+    key2 :: Bool,
+    key3 :: Maybe Prod
   }
   deriving (Eq, Show, Generic, MsgpackEncode, MsgpackDecode)
 
 dat :: Dat
-dat = Dat (Blob [[1, 2], [3]] (Map.fromList [(1, "1"), (2, "2")])) 13 (Prod "dat" 27)
+dat = Dat (Blob [[1, 2], [3]] (Map.fromList [(1, "1"), (2, "2")]) (NT "nt")) False (Just $ Prod "dat" 27)
 
 os :: String -> Object
 os = Util.string
@@ -48,17 +58,41 @@
 encodedBlob =
   ObjectMap $ Map.fromList [
     (os "key4", ObjectArray [ObjectArray [i 1, i 2], ObjectArray [i 3]]),
-    (os "key5", ObjectMap $ Map.fromList [(i 1, os "1"), (i 2, os "2")])
+    (os "key5", ObjectMap $ Map.fromList [(i 1, os "1"), (i 2, os "2")]),
+    (os "key6", os "nt")
     ]
 
 encoded :: Object
 encoded =
-  ObjectMap $ Map.fromList [(os "key1", encodedBlob), (os "key2", i 13), (os "key3", ObjectArray [os "dat", i 27])]
+  ObjectMap $ Map.fromList [
+    (os "key1", encodedBlob),
+    (os "key2", ObjectBool False),
+    (os "key3", ObjectArray [os "dat", i 27])
+    ]
 
 test_encode :: IO ()
 test_encode =
   assertEqual encoded (toMsgpack dat)
 
+doc2Text :: Either (Doc AnsiStyle) a -> Either Text a
+doc2Text =
+  mapLeft (renderStrict . layoutPretty defaultLayoutOptions)
+
 test_decode :: IO ()
 test_decode =
-  assertEqual (Right dat) (mapLeft (const ()) $ fromMsgpack encoded)
+  assertEqual (Right dat) (doc2Text $ fromMsgpack encoded)
+
+data Nope =
+  Nope {
+    present :: Int,
+    absent :: Maybe Int
+  }
+  deriving (Eq, Show, Generic, MsgpackDecode)
+
+encodedNope :: Object
+encodedNope =
+  ObjectMap $ Map.fromList [(os "present", i 5)]
+
+test_maybeMissing :: IO ()
+test_maybeMissing =
+  assertEqual (Right (Nope 5 Nothing)) (doc2Text $ fromMsgpack encodedNope)
