diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8047520391cb75d3f46acad5c87a720414f3c040..3a9f59557c622643ca8789eac51287a03c977222 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -400,7 +400,7 @@ if(${PUGS_HAS_MPI})
   endif()
   set(MPIEXEC_NUMPROC 3)
   set(MPIEXEC_PATH_FLAG --path)
-  set(MPI_LAUNCHER ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_NUMPROC} ${MPIEXEC_PATH_FLAG} ${PUGS_BINARY_DIR} ${MPIEXEC_OPTION_FLAGS})
+  set(MPI_LAUNCHER ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_NUMPROC} ${MPIEXEC_OPTION_FLAGS})
 endif()
 
 add_custom_target(all_unit_tests
@@ -427,6 +427,7 @@ endif()
 
 add_custom_target(run_mpi_unit_tests
   COMMAND ${MPI_LAUNCHER} "${PUGS_BINARY_DIR}/mpi_unit_tests"
+  WORKING_DIRECTORY ${PUGS_BINARY_DIR}
   DEPENDS run_unit_tests
   COMMENT ${RUN_MPI_UNIT_TESTS_COMMENT}
   )
diff --git a/src/language/ast/ASTModulesImporter.cpp b/src/language/ast/ASTModulesImporter.cpp
index 4cae0a921c139b3ae68a3decb0ce4f83876c4701..e1dc0043e689b506776540bb57e4851dc10883ae 100644
--- a/src/language/ast/ASTModulesImporter.cpp
+++ b/src/language/ast/ASTModulesImporter.cpp
@@ -26,10 +26,10 @@ ASTModulesImporter::_importModule(ASTNode& import_node)
     std::cout << " * importing '" << rang::fgB::green << module_name << rang::style::reset << "' module\n";
   }
 
-  m_module_repository.populateSymbolTable(module_name_node, m_symbol_table);
-  m_module_repository.registerOperators(module_name);
+  ModuleRepository::getInstance().populateSymbolTable(module_name_node, m_symbol_table);
+  ModuleRepository::getInstance().registerOperators(module_name);
   if (CheckpointResumeRepository::isCreated()) {
-    m_module_repository.registerCheckpointResume(module_name);
+    ModuleRepository::getInstance().registerCheckpointResume(module_name);
   }
 }
 
@@ -49,7 +49,7 @@ ASTModulesImporter::ASTModulesImporter(ASTNode& root_node) : m_symbol_table{*roo
 {
   Assert(root_node.is_root());
   OperatorRepository::instance().reset();
-  m_module_repository.populateMandatoryData(root_node, m_symbol_table);
+  ModuleRepository::getInstance().populateMandatoryData(root_node, m_symbol_table);
 
   this->_importAllModules(root_node);
 
diff --git a/src/language/ast/ASTModulesImporter.hpp b/src/language/ast/ASTModulesImporter.hpp
index 566155c4a19ecd00f0b049a29030c0036f212d8a..15ba8a7dc6cecbbb39bfb11c4d202d39200061a4 100644
--- a/src/language/ast/ASTModulesImporter.hpp
+++ b/src/language/ast/ASTModulesImporter.hpp
@@ -14,8 +14,6 @@ class ASTModulesImporter
   std::set<std::string> m_imported_modules;
   SymbolTable& m_symbol_table;
 
-  ModuleRepository m_module_repository;
-
   void _importModule(ASTNode& import_node);
   void _importAllModules(ASTNode& node);
 
@@ -23,7 +21,7 @@ class ASTModulesImporter
   const ModuleRepository&
   moduleRepository() const
   {
-    return m_module_repository;
+    return ModuleRepository::getInstance();
   }
 
   ASTModulesImporter(ASTNode& root_node);
diff --git a/src/language/modules/BinaryOperatorRegisterForVh.cpp b/src/language/modules/BinaryOperatorRegisterForVh.cpp
index 3eb83537323d91bbf6266cbefebf4d004d74c2be..d1c20cb78718568a3535e30f0b5c9ce255be1db6 100644
--- a/src/language/modules/BinaryOperatorRegisterForVh.cpp
+++ b/src/language/modules/BinaryOperatorRegisterForVh.cpp
@@ -1,6 +1,6 @@
 #include <language/modules/BinaryOperatorRegisterForVh.hpp>
 
-#include <language/modules/SchemeModule.hpp>
+#include <language/modules/SchemeModuleTypes.hpp>
 #include <language/utils/BinaryOperatorProcessorBuilder.hpp>
 #include <language/utils/DataHandler.hpp>
 #include <language/utils/DataVariant.hpp>
diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp
index d7b331a1dc606a83cf77dfe405b184b9ff143308..47e0183256413b7579165b26364dff68f0614a74 100644
--- a/src/language/modules/CoreModule.cpp
+++ b/src/language/modules/CoreModule.cpp
@@ -42,7 +42,7 @@
 #include <utils/checkpointing/ResumingManager.hpp>
 #include <utils/checkpointing/WriteOStream.hpp>
 
-#include <random>
+#include <language/modules/ModuleRepository.hpp>
 
 CoreModule::CoreModule() : BuiltinModule(true)
 {
@@ -219,3 +219,5 @@ CoreModule::registerCheckpointResume() const
 
 #endif   // PUGS_HAS_HDF5
 }
+
+ModuleRepository::Subscribe<CoreModule> core_module;
diff --git a/src/language/modules/DevUtilsModule.cpp b/src/language/modules/DevUtilsModule.cpp
index 361b4357eda0ebbfe4350cc6c64bbe72cfaa0829..4595ea6c9d9a45431b303c00b4de6defdda38b7b 100644
--- a/src/language/modules/DevUtilsModule.cpp
+++ b/src/language/modules/DevUtilsModule.cpp
@@ -1,5 +1,7 @@
 #include <language/modules/DevUtilsModule.hpp>
 
+#include <language/modules/ModuleRepository.hpp>
+
 #include <dev/ParallelChecker.hpp>
 #include <language/modules/MeshModuleTypes.hpp>
 #include <language/modules/SchemeModuleTypes.hpp>
@@ -126,3 +128,5 @@ DevUtilsModule::registerOperators() const
 void
 DevUtilsModule::registerCheckpointResume() const
 {}
+
+ModuleRepository::Subscribe<DevUtilsModule> dev_utils_module;
diff --git a/src/language/modules/LinearSolverModule.cpp b/src/language/modules/LinearSolverModule.cpp
index aef6470d2455909f5ad2d307aa4e5cb859b8bcbb..d3e2de0faeb52c213f372e3a751f075ea2d735d7 100644
--- a/src/language/modules/LinearSolverModule.cpp
+++ b/src/language/modules/LinearSolverModule.cpp
@@ -1,5 +1,7 @@
 #include <language/modules/LinearSolverModule.hpp>
 
+#include <language/modules/ModuleRepository.hpp>
+
 #include <algebra/LinearSolver.hpp>
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 #include <language/utils/TypeDescriptor.hpp>
@@ -98,3 +100,5 @@ LinearSolverModule::registerOperators() const
 void
 LinearSolverModule::registerCheckpointResume() const
 {}
+
+ModuleRepository::Subscribe<LinearSolverModule> linear_solver_module;
diff --git a/src/language/modules/MathFunctionRegisterForVh.cpp b/src/language/modules/MathFunctionRegisterForVh.cpp
index b31fe47d0eba87ff2e7f0823a530bf170e410d6c..d9a30e86996a9cd6b99af63d64a8ab33264c7fe3 100644
--- a/src/language/modules/MathFunctionRegisterForVh.cpp
+++ b/src/language/modules/MathFunctionRegisterForVh.cpp
@@ -1,6 +1,7 @@
 #include <language/modules/MathFunctionRegisterForVh.hpp>
 
 #include <language/modules/SchemeModule.hpp>
+#include <language/modules/SchemeModuleTypes.hpp>
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 #include <language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
diff --git a/src/language/modules/MathModule.cpp b/src/language/modules/MathModule.cpp
index 19a35a1529b1b65310c3c51d69fe4c5d02dc4d8a..1caea452428125e7a1c16aa88cb8278a5685fb35 100644
--- a/src/language/modules/MathModule.cpp
+++ b/src/language/modules/MathModule.cpp
@@ -1,5 +1,6 @@
 #include <language/modules/MathModule.hpp>
 
+#include <language/modules/ModuleRepository.hpp>
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 
 #include <cmath>
@@ -136,3 +137,5 @@ MathModule::registerOperators() const
 void
 MathModule::registerCheckpointResume() const
 {}
+
+ModuleRepository::Subscribe<MathModule> math_module;
diff --git a/src/language/modules/MeshModule.cpp b/src/language/modules/MeshModule.cpp
index c76260ce58c75c130e4638054fc394458fedbf63..c060da50d6da17915937edda6f5403a9e604355e 100644
--- a/src/language/modules/MeshModule.cpp
+++ b/src/language/modules/MeshModule.cpp
@@ -1,5 +1,7 @@
 #include <language/modules/MeshModule.hpp>
 
+#include <language/modules/ModuleRepository.hpp>
+
 #include <algebra/TinyVector.hpp>
 #include <language/node_processor/ExecutionPolicy.hpp>
 #include <language/utils/BinaryOperatorProcessorBuilder.hpp>
@@ -160,27 +162,28 @@ MeshModule::MeshModule()
 
                                           ));
 
-  this
-    ->_addBuiltinFunction("interpolate",
-                          std::function(
+  this->_addBuiltinFunction("interpolate",
+                            std::function(
 
-                            [](std::shared_ptr<const MeshVariant> mesh_v, std::shared_ptr<const ItemType> item_type,
-                               const FunctionSymbolId& function_id) -> std::shared_ptr<const ItemValueVariant> {
-                              return ItemValueVariantFunctionInterpoler{mesh_v, *item_type, function_id}.interpolate();
-                            }
+                              [](std::shared_ptr<const MeshVariant> mesh_v, std::shared_ptr<const ItemType> item_type,
+                                 const FunctionSymbolId& function_id) -> std::shared_ptr<const ItemValueVariant> {
+                                return ItemValueVariantFunctionInterpoler{mesh_v, *item_type, function_id}
+                                  .interpolate();
+                              }
 
-                            ));
+                              ));
 
-  this->_addBuiltinFunction(
-    "interpolate_array",
-    std::function(
+  this->_addBuiltinFunction("interpolate_array",
+                            std::function(
 
-      [](std::shared_ptr<const MeshVariant> mesh_v, std::shared_ptr<const ItemType> item_type,
-         const std::vector<FunctionSymbolId>& function_id_list) -> std::shared_ptr<const ItemArrayVariant> {
-        return ItemArrayVariantFunctionInterpoler{mesh_v, *item_type, function_id_list}.interpolate();
-      }
+                              [](std::shared_ptr<const MeshVariant> mesh_v, std::shared_ptr<const ItemType> item_type,
+                                 const std::vector<FunctionSymbolId>& function_id_list)
+                                -> std::shared_ptr<const ItemArrayVariant> {
+                                return ItemArrayVariantFunctionInterpoler{mesh_v, *item_type, function_id_list}
+                                  .interpolate();
+                              }
 
-      ));
+                              ));
 
   this->_addBuiltinFunction("transform",
                             std::function(
@@ -442,3 +445,5 @@ MeshModule::registerCheckpointResume() const
 
 #endif   // PUGS_HAS_HDF5
 }
+
+ModuleRepository::Subscribe<MeshModule> mesh_module;
diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp
index 59689fb6fee512e45cd76c7c9d3cd5c11d543ee8..42d62fa0abac86a74a36379271482bc15b685997 100644
--- a/src/language/modules/ModuleRepository.cpp
+++ b/src/language/modules/ModuleRepository.cpp
@@ -1,14 +1,6 @@
 #include <language/modules/ModuleRepository.hpp>
 
 #include <language/ast/ASTNode.hpp>
-#include <language/modules/CoreModule.hpp>
-#include <language/modules/DevUtilsModule.hpp>
-#include <language/modules/LinearSolverModule.hpp>
-#include <language/modules/MathModule.hpp>
-#include <language/modules/MeshModule.hpp>
-#include <language/modules/SchemeModule.hpp>
-#include <language/modules/SocketModule.hpp>
-#include <language/modules/WriterModule.hpp>
 #include <language/utils/BasicAffectationRegistrerFor.hpp>
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 #include <language/utils/CheckpointResumeRepository.hpp>
@@ -19,7 +11,6 @@
 
 #include <utils/PugsAssert.hpp>
 
-#include <algorithm>
 #include <set>
 
 void
@@ -52,18 +43,6 @@ ModuleRepository::_subscribe(std::unique_ptr<IModule> m)
   Assert(success, "module has already been subscribed");
 }
 
-ModuleRepository::ModuleRepository()
-{
-  this->_subscribe(std::make_unique<CoreModule>());
-  this->_subscribe(std::make_unique<LinearSolverModule>());
-  this->_subscribe(std::make_unique<MathModule>());
-  this->_subscribe(std::make_unique<MeshModule>());
-  this->_subscribe(std::make_unique<SchemeModule>());
-  this->_subscribe(std::make_unique<SocketModule>());
-  this->_subscribe(std::make_unique<DevUtilsModule>());
-  this->_subscribe(std::make_unique<WriterModule>());
-}
-
 template <typename NameEmbedderMapT, typename EmbedderTableT>
 void
 ModuleRepository::_populateEmbedderTableT(const ASTNode& module_node,
diff --git a/src/language/modules/ModuleRepository.hpp b/src/language/modules/ModuleRepository.hpp
index 407d7b55bd9b7c8454159a315b9c2f7a256eecb6..b2e217b9374bb918e75d5a6dbe028ae4f8e12923 100644
--- a/src/language/modules/ModuleRepository.hpp
+++ b/src/language/modules/ModuleRepository.hpp
@@ -32,6 +32,23 @@ class ModuleRepository
                             SymbolTable& symbol_table);
 
  public:
+  static ModuleRepository&
+  getInstance()
+  {
+    static ModuleRepository m_instance;
+    return m_instance;
+  }
+
+  template <typename ModuleT>
+  struct Subscribe
+  {
+    Subscribe()
+    {
+      static_assert(std::is_base_of_v<IModule, ModuleT>, "module must inherit IModule interface");
+      ModuleRepository::getInstance()._subscribe(std::make_unique<ModuleT>());
+    }
+  };
+
   void populateSymbolTable(const ASTNode& module_name_node, SymbolTable& symbol_table);
   void populateMandatoryData(const ASTNode& root_node, SymbolTable& symbol_table);
   void registerOperators(const std::string& module_name);
@@ -46,7 +63,10 @@ class ModuleRepository
   ModuleRepository(const ModuleRepository&) = delete;
   ModuleRepository(ModuleRepository&&)      = delete;
 
-  ModuleRepository();
+ private:
+  ModuleRepository() = default;
+
+ public:
   ~ModuleRepository() = default;
 };
 
diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp
index f1a7d8d73606a6cd71e4aa6b4f7253f8773a804e..40cc703cc6dcc0029da81366fb95134fc1329599 100644
--- a/src/language/modules/SchemeModule.cpp
+++ b/src/language/modules/SchemeModule.cpp
@@ -1,4 +1,7 @@
 #include <language/modules/SchemeModule.hpp>
+#include <language/modules/SchemeModuleTypes.hpp>
+
+#include <language/modules/ModuleRepository.hpp>
 
 #include <analysis/GaussLegendreQuadratureDescriptor.hpp>
 #include <analysis/GaussLobattoQuadratureDescriptor.hpp>
@@ -809,3 +812,5 @@ SchemeModule::registerCheckpointResume() const
 
 #endif   // PUGS_HAS_HDF5
 }
+
+ModuleRepository::Subscribe<SchemeModule> scheme_module;
diff --git a/src/language/modules/SchemeModule.hpp b/src/language/modules/SchemeModule.hpp
index c61b3084406dbd8ae9889c79b4172195daaa6fe8..cf169175c4b46f7364799e16bdb4b84633d1f61c 100644
--- a/src/language/modules/SchemeModule.hpp
+++ b/src/language/modules/SchemeModule.hpp
@@ -2,7 +2,6 @@
 #define SCHEME_MODULE_HPP
 
 #include <language/modules/BuiltinModule.hpp>
-#include <language/modules/SchemeModuleTypes.hpp>
 
 class SchemeModule : public BuiltinModule
 {
diff --git a/src/language/modules/SocketModule.cpp b/src/language/modules/SocketModule.cpp
index 79321d088f960e0bb7450c82820cf6568e79d174..9c2ecdbe1b40730d0181d7f4ee6f3bf396f70a34 100644
--- a/src/language/modules/SocketModule.cpp
+++ b/src/language/modules/SocketModule.cpp
@@ -1,5 +1,7 @@
 #include <language/modules/SocketModule.hpp>
 
+#include <language/modules/ModuleRepository.hpp>
+
 #include <language/utils/BinaryOperatorProcessorBuilder.hpp>
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 #include <language/utils/CheckpointResumeRepository.hpp>
@@ -271,3 +273,5 @@ SocketModule::registerCheckpointResume() const
                            throw NotImplementedError("checkpoint/resume with sockets");
                          }));
 }
+
+ModuleRepository::Subscribe<SocketModule> socket_module;
diff --git a/src/language/modules/UnaryOperatorRegisterForVh.cpp b/src/language/modules/UnaryOperatorRegisterForVh.cpp
index e2e9c2db9b72a9a687806d24dee836cfd37a22e8..3d52ab54687eabcd6162536d88325b3285d45e1f 100644
--- a/src/language/modules/UnaryOperatorRegisterForVh.cpp
+++ b/src/language/modules/UnaryOperatorRegisterForVh.cpp
@@ -1,6 +1,6 @@
 #include <language/modules/UnaryOperatorRegisterForVh.hpp>
 
-#include <language/modules/SchemeModule.hpp>
+#include <language/modules/SchemeModuleTypes.hpp>
 #include <language/utils/DataHandler.hpp>
 #include <language/utils/DataVariant.hpp>
 #include <language/utils/EmbeddedDiscreteFunctionOperators.hpp>
diff --git a/src/language/modules/WriterModule.cpp b/src/language/modules/WriterModule.cpp
index 6d84506501de277f1970c13a7c24cd587ed79f20..e524a885639ac9a2a2da6330422565447bcb347d 100644
--- a/src/language/modules/WriterModule.cpp
+++ b/src/language/modules/WriterModule.cpp
@@ -1,7 +1,9 @@
 #include <language/modules/WriterModule.hpp>
 
-#include <language/modules/MeshModule.hpp>
-#include <language/modules/SchemeModule.hpp>
+#include <language/modules/ModuleRepository.hpp>
+
+#include <language/modules/MeshModuleTypes.hpp>
+#include <language/modules/SchemeModuleTypes.hpp>
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 #include <language/utils/CheckpointResumeRepository.hpp>
 #include <language/utils/TypeDescriptor.hpp>
@@ -242,3 +244,5 @@ WriterModule::registerCheckpointResume() const
 
 #endif   // PUGS_HAS_HDF5
 }
+
+ModuleRepository::Subscribe<WriterModule> writer_module{};