diff --git a/lib/Proteome/PersistBuffers.hs b/lib/Proteome/PersistBuffers.hs
--- a/lib/Proteome/PersistBuffers.hs
+++ b/lib/Proteome/PersistBuffers.hs
@@ -7,7 +7,7 @@
 ) where
 
 import GHC.Generics
-import Control.Monad (filterM)
+import Control.Monad (filterM, when)
 import Control.Monad.IO.Class (liftIO)
 import Control.Monad.Trans.Except (runExceptT)
 import Data.Aeson (ToJSON(toEncoding), FromJSON, genericToEncoding, defaultOptions)
@@ -63,10 +63,11 @@
 decodePersistBuffers :: FilePath -> Proteome (Either String PersistBuffers)
 decodePersistBuffers path = runExceptT $ persistLoad (path </> "buffers")
 
--- TODO only restore current buffer when none is active
 restoreBuffers :: PersistBuffers -> Proteome ()
 restoreBuffers (PersistBuffers current' buffers') = do
-  mapM_ edit current'
+  active <- vim_get_current_buffer'
+  name <- buffer_get_name' active
+  when (null name) $ mapM_ edit current'
   traverse_ (\a -> vim_command' ("silent! badd " ++ a)) buffers'
 
 unsafeLoadBuffers :: FilePath -> Proteome ()
diff --git a/lib/Proteome/Tags.hs b/lib/Proteome/Tags.hs
--- a/lib/Proteome/Tags.hs
+++ b/lib/Proteome/Tags.hs
@@ -16,8 +16,10 @@
 import System.Process (readCreateProcessWithExitCode)
 import qualified System.Process as Proc (proc, CreateProcess(cwd))
 import System.FilePath ((</>))
-import System.Directory (doesFileExist, removePathForcibly)
+import System.Directory (doesFileExist, removePathForcibly, renameFile)
+import UnliftIO (tryIO)
 import Ribosome.Config.Setting (setting)
+import Ribosome.Data.Ribo (lockOrSkip)
 import qualified Ribosome.Data.Ribo as Ribo (inspect, modify)
 import Ribosome.Data.Errors (Errors(Errors), Error(Error), ComponentName(ComponentName))
 import Ribosome.Internal.IO (forkNeovim)
@@ -48,13 +50,24 @@
       ("root", root)
       ]
 
+tempname :: String -> String
+tempname name = name ++ ".tmp"
+
 deleteTags :: ProjectRoot -> Proteome ()
 deleteTags (ProjectRoot root) = do
   name <- setting S.tagsFileName
-  let path = root </> name
+  let path = root </> tempname name
   exists <- liftIO $ doesFileExist path
   when exists $ liftIO $ removePathForcibly path
 
+replaceTags :: ProjectRoot -> Proteome ()
+replaceTags (ProjectRoot root) = do
+  name <- setting S.tagsFileName
+  let temppath = root </> tempname name
+  let path = root </> name
+  _ <- liftIO $ tryIO $ renameFile temppath path
+  return ()
+
 storeError :: ComponentName -> [String] -> Errors -> Errors
 storeError name msg (Errors errors) =
   Errors (Map.adjust (err:) name errors)
@@ -71,15 +84,13 @@
 tagsProcess (ProjectRoot root) cmd args =
   readCreateProcessWithExitCode (Proc.proc cmd (words args)) { Proc.cwd = Just root } ""
 
--- TODO write to temp file, move to actual file after
--- TODO lock process in state to avoid multiple processes trying to access the file
 executeTags :: ProjectRoot -> String -> String -> Proteome ()
 executeTags root@(ProjectRoot rootS) cmd args = do
   deleteTags root
   debugS $ "executing tags: `" ++ cmd ++ " " ++ args ++ "` in directory " ++ rootS
   (exitcode, _, stderr) <- liftIO $ tagsProcess root cmd args
   case exitcode of
-    ExitSuccess -> return ()
+    ExitSuccess -> replaceTags root
     ExitFailure _ -> notifyError stderr
 
 regenerateTags :: ProjectRoot -> [ProjectLang] -> Proteome ()
@@ -87,7 +98,7 @@
   cmd <- setting S.tagsCommand
   args <- setting S.tagsArgs
   fileName <- setting S.tagsFileName
-  let thunk = executeTags root cmd (formatTagsArgs langs root fileName args)
+  let thunk = executeTags root cmd (formatTagsArgs langs root (tempname fileName) args)
   fork <- setting S.tagsFork
   _ <- if fork then forkNeovim thunk else thunk
   return ()
@@ -101,4 +112,4 @@
 proTags = do
   main <- Ribo.inspect mainProject
   extra <- Ribo.inspect projects
-  traverse_ projectTags (main : extra)
+  lockOrSkip "tags" $ traverse_ projectTags (main : extra)
diff --git a/proteome.cabal b/proteome.cabal
--- a/proteome.cabal
+++ b/proteome.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 68f91b72a046fbccc15d92486eab9379d3a2f0e0526b5c2a5029ea5df16cc43d
+-- hash: 5fba2c152bddc90f0d4e9642ee33b0cd2b1591db5f4aec89a3d3558ef9c00e17
 
 name:           proteome
-version:        0.3.9.0
+version:        0.3.10.0
 synopsis:       neovim project manager
 description:    Please see the README on GitHub at <https://github.com/tek/proteome-hs>
 category:       Neovim
