diff --git a/lib/Proteome/Tags.hs b/lib/Proteome/Tags.hs
--- a/lib/Proteome/Tags.hs
+++ b/lib/Proteome/Tags.hs
@@ -8,6 +8,7 @@
 import Control.Monad (when)
 import Control.Monad.IO.Class (liftIO)
 import Control.Lens (over)
+import Data.Foldable (traverse_)
 import Data.List (intercalate)
 import qualified Data.Map.Strict as Map (adjust)
 import Data.Maybe (maybeToList)
@@ -20,7 +21,7 @@
 import qualified Ribosome.Data.Ribo as Ribo (inspect, modify)
 import Ribosome.Data.Errors (Errors(Errors), Error(Error), ComponentName(ComponentName))
 import Ribosome.Internal.IO (forkNeovim)
-import Proteome.Data.Env (Env(mainProject))
+import Proteome.Data.Env (Env(mainProject, projects))
 import qualified Proteome.Data.Env as Env (_errors)
 import Proteome.Data.Proteome (Proteome)
 import Proteome.Data.Project (
@@ -31,6 +32,7 @@
   langOrType,
   )
 import qualified Proteome.Settings as S (tagsCommand, tagsArgs, tagsFork, tagsFileName)
+import Proteome.Log
 
 replaceFormatItem :: String -> (String, String) -> String
 replaceFormatItem original (placeholder, replacement) =
@@ -42,7 +44,7 @@
   where
     formats = [
       ("langsComma", intercalate "," $ fmap (\(ProjectLang l) -> l) langs),
-      ("tagFile", fileName),
+      ("tagFile", root </> fileName),
       ("root", root)
       ]
 
@@ -61,13 +63,19 @@
     time = 0
 
 notifyError :: String -> Proteome ()
-notifyError e =
+notifyError e = do
+  infoS $ "tags failed: " ++ e
   Ribo.modify $ over Env._errors (storeError (ComponentName "ctags") [e])
 
+tagsProcess :: ProjectRoot -> String -> String -> IO (ExitCode, String, String)
+tagsProcess (ProjectRoot root) cmd args =
+  readCreateProcessWithExitCode (Proc.proc cmd (words args)) { Proc.cwd = Just root } ""
+
 executeTags :: ProjectRoot -> String -> String -> Proteome ()
-executeTags (ProjectRoot root) cmd args = do
-  deleteTags (ProjectRoot root)
-  (exitcode, _, stderr) <- liftIO $ readCreateProcessWithExitCode ((Proc.proc cmd [args]) { Proc.cwd = (Just root) }) ""
+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 ()
     ExitFailure _ -> notifyError stderr
@@ -82,10 +90,13 @@
   _ <- if fork then forkNeovim thunk else thunk
   return ()
 
+projectTags :: Project -> Proteome ()
+projectTags (Project (DirProject _ root tpe) _ lang langs ) =
+  regenerateTags root (maybeToList (langOrType lang tpe) ++ langs)
+projectTags _ = return ()
+
 proTags :: Proteome ()
 proTags = do
   main <- Ribo.inspect mainProject
-  case main of
-    Project (DirProject _ root tpe) _ lang langs ->
-      regenerateTags root (maybeToList (langOrType lang tpe) ++ langs)
-    _ -> return ()
+  extra <- Ribo.inspect projects
+  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: ee165e2612b4794394cbe7da84f7fb9150ea73099aadb78e479de5bb1db4ea24
+-- hash: eaeaa5e19fbd3b145b1a7a2b04d61f2f2b8d7f0e7cb6e0653b18a41a8b2105c1
 
 name:           proteome
-version:        0.3.5.0
+version:        0.3.6.0
 synopsis:       neovim project manager
 description:    Please see the README on GitHub at <https://github.com/tek/proteome-hs>
 category:       Neovim
diff --git a/test/u/TagsSpec.hs b/test/u/TagsSpec.hs
--- a/test/u/TagsSpec.hs
+++ b/test/u/TagsSpec.hs
@@ -37,10 +37,10 @@
   Ribo.modify $ set (_mainProject._meta) (main root)
   Ribo.modify $ set (_mainProject._lang) (Just (ProjectLang "idris"))
   updateSetting S.tagsCommand "touch"
-  updateSetting S.tagsArgs "tags-{langsComma}-{tagFile}"
+  updateSetting S.tagsArgs "tags-{langsComma}"
   updateSetting S.tagsFork False
   proTags
-  let tagsFile = root </> "tags-idris-.tags"
+  let tagsFile = root </> "tags-idris"
   exists <- liftIO $ doesFileExist tagsFile
   liftIO $ assertBool exists
 
