diff --git a/core/base/CbmDigiManager.h b/core/base/CbmDigiManager.h
index e6e90578ca248aa8a1750872720acc09d5a5e407..29e8062610a33a123a86df21f69f326536d6ab1b 100644
--- a/core/base/CbmDigiManager.h
+++ b/core/base/CbmDigiManager.h
@@ -69,6 +69,16 @@ public:
     return nullptr;
   }
 
+  /** @brief Access to a digi branch
+   ** @param system System identifier
+   ** @return Digi branch
+   **/
+  CbmDigiBranchBase* GetBranch(ECbmModuleId system)
+  {
+    auto it = fBranches.find(system);
+    return (it != fBranches.end() ? it->second : nullptr);
+  }
+
 
   /** @brief Get a match object
      ** @param  System identifier (ECbmModuleId)
diff --git a/core/data/CMakeLists.txt b/core/data/CMakeLists.txt
index 1180f46484d2618db05506edad90bd3fe23a694c..08fdae3eb5e4e54dbbdb57a4f9243fd80c5565bc 100644
--- a/core/data/CMakeLists.txt
+++ b/core/data/CMakeLists.txt
@@ -141,6 +141,11 @@ set(LINKDEF DataLinkDef.h)
 set(LIBRARY_NAME CbmData)
 set(DEPENDENCIES Base)
 
+# Generate list of headers from the list of source files and add some extra header files 
+CHANGE_FILE_EXTENSION(*.cxx *.h HEADERS "${SRCS}")
+list(APPEND HEADERS global/CbmDigiEvent.h)
+
+
 GENERATE_LIBRARY()
 
 # Install file which has no corresponding source file
diff --git a/core/data/DataLinkDef.h b/core/data/DataLinkDef.h
index 75ecb0560e8e03cac23ae9c9bcfffacda7a7011c..d9c23c0b51e3576b9ea9384992302f2c23d6d355 100644
--- a/core/data/DataLinkDef.h
+++ b/core/data/DataLinkDef.h
@@ -89,9 +89,11 @@
 #pragma link C++ class CbmPsdAddress;
 #pragma link C++ class CbmPsdMCbmHit;
 
+// --- data/global
 #pragma link C++ class CbmGlobalTrack + ;
 #pragma link C++ class CbmTofTrack + ;
 #pragma link C++ class CbmVertex + ;
+#pragma link C++ class std::vector < CbmDigiEvent>;
 
 #pragma link C++ class stsxyter::Message;
 #pragma link C++ class gdpbv100::Message;
@@ -131,6 +133,7 @@
 #pragma link C++ class CbmDigiVector < CbmPsdDsp> + ;
 #pragma link C++ class vector < CbmEventStore> + ;
 
+/* clang-format off */
 #pragma read sourceClass="CbmStsDigi" version="[7]" targetClass="CbmStsDigi" \
     source="Long64_t fTime; Int_t fAddress; UShort_t fChannel; UShort_t fCharge" \
     target="" \
@@ -163,6 +166,8 @@
                      + ((chId & ((1 << 6) - 1)) << 22) \
                      + ((rpcType & ((1 << 4) - 1)) << 28); \
          }"
+/* clang-format on */
+
 
 #pragma read sourceClass = "CbmTofHit" version = "[1-4]" targetClass = "CbmTofHit" source = "" target = "" include =   \
   "Logger.h" code                                                                                     = "{ \
diff --git a/core/data/base/CbmDigiBranch.h b/core/data/base/CbmDigiBranch.h
index 73c9ca535b485108fc79ee2af735e096ef55538e..3bcb83fde3877bf97d7eaa511daebe3b428806af 100644
--- a/core/data/base/CbmDigiBranch.h
+++ b/core/data/base/CbmDigiBranch.h
@@ -175,7 +175,7 @@ public:
 
   // -----------------------------------------------------------------------
   /** @brief Get branch pointer
-		 ** @return Pointer to the connected data container
+		 ** @return Pointer to the connected data container (const)
 		 ** A std::vector is first looked for; if not found, a TClonesArray
 		 ** is looked for.
 		 ** Returns a null pointer if the branch is not present.
diff --git a/macro/CMakeLists.txt b/macro/CMakeLists.txt
index c6815af251db3a22346f1d7f5f087b97592bfeba..6173cf2321cfae8faf0fa473ed69e7899aba84f9 100644
--- a/macro/CMakeLists.txt
+++ b/macro/CMakeLists.txt
@@ -4,7 +4,9 @@ add_subdirectory(mcbm)
 add_subdirectory(mvd)
 add_subdirectory(much)
 add_subdirectory(include)
-
+if (${CMAKE_CXX_STANDARD} EQUAL 17)
+  add_subdirectory (reco)
+endif()
 
 #--- Additional tests for nightly builds
 If(NOT ${CBM_TEST_MODEL} MATCHES Experimental)
diff --git a/macro/reco/CMakeLists.txt b/macro/reco/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..852851e3ebb7965a7ebe56cc7fd3c1b43f1a0e0d
--- /dev/null
+++ b/macro/reco/CMakeLists.txt
@@ -0,0 +1,157 @@
+# CMakeList.txt for macro/reco
+# Defines regular tests
+# V. Friese, November 2021
+
+# =====   Generate the needed shell scripts   ================================
+GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_tra_file.C)
+GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_tra_beam.C)
+GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_digi.C)
+GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/reco/reco_digi.C)
+# ============================================================================
+
+
+# =====   Copy the .rootrc file into the directory from which root is executed
+# --- Otherwise the rootalias file is not loaded
+file(COPY ${CBMROOT_SOURCE_DIR}/macro/include/.rootrc
+	DESTINATION ${CBMROOT_BINARY_DIR}/macro/reco)
+# ============================================================================
+
+
+# =====   Define variables for tests   =======================================
+Set(randomSeed 1)
+if(${CBM_TEST_MODEL} MATCHES Weekly)
+  Set(nEvents 100)
+else()
+  Set(nEvents 3)
+endIf()
+
+math(EXPR timeOutTime "${nEvents} * 200")
+math(EXPR nBeam "${nEvents} * 3")
+
+set(datadir ${CBMROOT_BINARY_DIR}/macro/reco/data)
+# ============================================================================
+
+
+# =====   Define the different setups to be tested with   ====================
+if(NOT ${CBM_TEST_MODEL} MATCHES Experimental )
+  List(APPEND cbm_setup sis100_hadron sis100_electron sis100_muon_lmvm
+  	sis100_muon_jpsi sis300_electron)
+else()
+  List(APPEND cbm_setup sis100_hadron)
+endif()
+# ============================================================================
+
+
+# =====   Cleanup the data directory   =======================================
+add_test(reco_cleanup ${CMAKE_COMMAND}
+	-P ${CMAKE_SOURCE_DIR}/cmake/scripts/cleanmacrodir.cmake)
+set_tests_properties(reco_cleanup PROPERTIES
+	TIMEOUT ${timeOutTime}
+	FIXTURES_SETUP reco_cleanup
+)
+# ============================================================================
+
+
+# =====   Define tests for each setup   ======================================
+foreach(setup IN LISTS cbm_setup)
+
+  # --- Short name for setup
+  if(setup MATCHES sis100_hadron)
+  	set(sname s100h)
+  elseif(setup MATCHES sis100_electron)
+  	set(sname s100e)
+  elseif(setup MATCHES sis100_muon_lmvm)
+  	set(sname s100m2)
+  elseif(setup MATCHES sis100_muon_jpsi)
+  	set(sname s100m3)
+  elseif(setup MATCHES sis300_electron)
+  	set(sname s300e)
+  else()
+  	set(sname test)
+  endif()
+
+  # --- Test reco_tra_coll
+  # --- Transport run with collision events, using run_tra_file.C
+  set(testname reco_tra_coll_${sname})
+  set(input ${CBMROOT_SOURCE_DIR}/input/urqmd.auau.10gev.centr.root)
+  set(output ${datadir}/${sname}_coll)
+  add_test(${testname} ${CBMROOT_BINARY_DIR}/macro/run/run_tra_file.sh
+  	\"${input}\" ${nEvents} \"${output}\" \"${setup}\" kGeant3 ${randomSeed})
+  set_tests_properties(${testname} PROPERTIES
+  	TIMEOUT ${timeOutTime}
+  	PASS_REGULAR_EXPRESSION "Macro finished successfully"
+  	FIXTURES_REQUIRED reco_cleanup
+  	FIXTURES_SETUP fixt_tra_coll_${setup}
+  	RESOURCE_LOCK collParDb_${setup}
+  )
+
+  # --- Test run_tra_sign
+  # --- Transport run with signal events, using run_tra_file.C
+  set(testname reco_tra_sign_${sname})
+  set(input ${CBMROOT_SOURCE_DIR}/input/pluto.auau.8gev.omega.mpmm.0001.root)
+  set(output ${datadir}/${sname}_sign)
+   add_test(${testname} ${CBMROOT_BINARY_DIR}/macro/run/run_tra_file.sh
+  	\"${input}\" ${nEvents} \"${output}\" \"${setup}\" kGeant3 ${randomSeed})
+  set_tests_properties(${testname} PROPERTIES
+  	TIMEOUT ${timeOutTime}
+  	PASS_REGULAR_EXPRESSION "Macro finished successfully"
+  	FIXTURES_REQUIRED reco_cleanup
+  	FIXTURES_SETUP fixt_tra_sign_${setup}
+  	RESOURCE_LOCK signParDb_${setup}
+  )
+
+  # --- Test run_tra_beam
+  # --- Transport run with beam events, using run_tra_beam.C
+  set(testname reco_tra_beam_${sname})
+  set(output ${datadir}/${sname}_beam)
+   add_test(${testname} ${CBMROOT_BINARY_DIR}/macro/run/run_tra_beam.sh
+  	${nBeam} \"Au\" 10 -1 \"${output}\" \"${setup}\" kGeant3 ${randomSeed})
+  set_tests_properties(${testname} PROPERTIES
+  	TIMEOUT ${timeOutTime}
+  	PASS_REGULAR_EXPRESSION "Macro finished successfully"
+  	FIXTURES_REQUIRED reco_cleanup
+  	FIXTURES_SETUP fixt_tra_beam_${setup}
+  	RESOURCE_LOCK beamParDb_${setup}
+  )
+
+  # --- Test run_digi_ts
+  # --- Detector response simulation, time-based, using run_digi.C
+  set(testname reco_digi_${sname})
+  set(eventrate 1.e7)
+  set(beamrate 1.e9)
+  set(tslength 1.e6)
+  add_test(${testname} ${CBMROOT_BINARY_DIR}/macro/run/run_digi.sh
+  	\"${datadir}/${sname}_coll\" -1 \"${datadir}/${sname}\"\ ${eventrate} ${tslength}
+  	\"${datadir}/${sname}_sign\" \"${datadir}/${sname}_beam\" ${beamrate})
+  set_tests_properties(${testname} PROPERTIES
+  	TIMEOUT ${timeOutTime}
+  	PASS_REGULAR_EXPRESSION "Macro finished successfully"
+ 	FIXTURES_REQUIRED "fixt_tra_coll_${setup};fixt_tra_sign_${setup};fixt_tra_beam_${setup}"
+  	FIXTURES_SETUP fixt_digi_ts_${setup}
+ 	RESOURCE_LOCK collParDb_${setup}
+  )
+
+  # --- Test reco_digi
+  # --- Reconstruction from time-based simulation
+  set(testname reco_reco_digi_${sname})
+  add_test(${testname} ${MACRODIR}/reco_digi.sh
+  	\"${datadir}/${sname}\" -1 0 \"${datadir}/${sname}\" \"${setup}\"
+  	\"${datadir}/${sname}_coll\")
+  set_tests_properties(${testname} PROPERTIES
+  	TIMEOUT ${timeOutTime}
+  	PASS_REGULAR_EXPRESSION "Macro finished successfully"
+	FIXTURES_REQUIRED fixt_digi_ts_${setup}
+	FIXTURES_SETUP fixt_reco_digi_${setup}
+ 	RESOURCE_LOCK collParDb_${setup}
+  )
+
+endforeach(setup IN LISTS cbm_setup)
+# ============================================================================
+
+# ============================================================================
+
+Install(FILES .rootrc run_tra_file.C run_tra_beam.C
+              run_digi.C reco_digi.C 
+        DESTINATION share/cbmroot/macro/reco
+       )
+Install(CODE "FILE(MAKE_DIRECTORY \${CMAKE_INSTALL_PREFIX}/share/cbmroot/macro/reco/data)")
diff --git a/macro/reco/reco_digi.C b/macro/reco/reco_digi.C
new file mode 100644
index 0000000000000000000000000000000000000000..88b993476beba6d0f0b729dd5cf857bf0e690c62
--- /dev/null
+++ b/macro/reco/reco_digi.C
@@ -0,0 +1,175 @@
+/* Copyright (C) 2020-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer], Dominik Smith */
+
+
+// --- Includes needed for IDE
+#include <RtypesCore.h>
+#if !defined(__CLING__)
+#include "CbmDefs.h"
+#include "CbmSetup.h"
+#include "CbmTaskBuildEvents.h"
+
+#include <FairFileSource.h>
+#include <FairLogger.h>
+#include <FairMonitor.h>
+#include <FairParAsciiFileIo.h>
+#include <FairParRootFileIo.h>
+#include <FairRunAna.h>
+#include <FairRuntimeDb.h>
+#include <FairSystemInfo.h>
+
+#include <TStopwatch.h>
+#endif
+
+
+/** @brief Macro for CBM reconstruction from digi level
+ ** @author Volker Friese <v.friese@gsi.de>
+ ** @since  15 November 2021
+ ** @param input          Name of input file (w/o extension .raw.root)
+ ** @param nTimeSlices    Number of time-slices to process
+ ** @param firstTimeSlice First time-slice (entry) to be processed
+ ** @param output         Name of output file (w/o extension .rec.root)
+ ** @param setup          Name of predefined geometry setup
+ ** @param paramFile      Parameter ROOT file (w/o extension .par.root)
+ **
+ ** Reconstruction from digi level. Currently included stages:
+ ** - Event building (CbmTaskBuildEvents) (STS only)
+ **
+ ** TODO: To be expanded with the progress of the algo project.
+ **
+ ** The file names must be specified without extensions. The convention is
+ ** that the raw (input) file is [input].raw.root. The output file
+ ** will be [input].rec.root if not specified by the user. The parameter file
+ ** has the extension .par.root. It is assumed to be [input].par.root if
+ ** not specified by the user.
+ **
+ ** If no argument is specified, the input will be set to "test". This allows
+ ** to execute the macro chain (run_tra_file.C, run_digi.C and run_reco.C)
+ ** from the ROOT prompt without user intervention.
+ **
+ **/
+void reco_digi(TString input = "", Int_t nTimeSlices = -1, Int_t firstTimeSlice = 0, TString output = "",
+               TString setup = "sis100_electron", TString paramFile = "")
+{
+
+  // ========================================================================
+  //          Adjust this part according to your requirements
+
+  // --- Logger settings ----------------------------------------------------
+  TString logLevel     = "INFO";
+  TString logVerbosity = "LOW";
+  // ------------------------------------------------------------------------
+
+  // -----   Environment   --------------------------------------------------
+  TString myName = "run_reco_algo";                // this macro's name for screen output
+  TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
+  // ------------------------------------------------------------------------
+
+
+  // -----   In- and output file names   ------------------------------------
+  if (input.IsNull()) input = "test";
+  TString rawFile = input + ".raw.root";
+  TString traFile = input + ".tra.root";
+  if (output.IsNull()) output = input;
+  TString outFile = output + ".reco.root";
+  TString monFile = output + ".moni_reco.root";
+  if (paramFile.IsNull()) paramFile = input;
+  TString parFile = paramFile + ".par.root";
+  std::cout << "Inputfile " << rawFile << std::endl;
+  std::cout << "Outfile " << outFile << std::endl;
+  std::cout << "Parfile " << parFile << std::endl;
+
+  // -----   Load the geometry setup   -------------------------------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Loading setup " << setup << std::endl;
+  CbmSetup* geo = CbmSetup::Instance();
+  geo->LoadSetup(setup);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Timer   --------------------------------------------------------
+  TStopwatch timer;
+  timer.Start();
+  // ------------------------------------------------------------------------
+
+
+  // -----   FairRunAna   ---------------------------------------------------
+  FairRunAna* run             = new FairRunAna();
+  FairFileSource* inputSource = new FairFileSource(rawFile);
+  run->SetSource(inputSource);
+  run->SetOutputFile(outFile);
+  run->SetGenerateRunInfo(kTRUE);
+  FairMonitor::GetMonitor()->EnableMonitor(kTRUE, monFile);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Logger settings   ----------------------------------------------
+  FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data());
+  FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data());
+  // ------------------------------------------------------------------------
+
+
+  // -----   Event building   -----------------------------------------------
+  CbmTaskBuildEvents* evtBuild = new CbmTaskBuildEvents();
+  evtBuild->SetTimeWindow(-20., 30.);  // event build window for STS
+  run->AddTask(evtBuild);
+  LOG(info) << myName << ": Addes task " << evtBuild->GetName();
+  // ------------------------------------------------------------------------
+
+
+  // -----  Parameter database   --------------------------------------------
+  std::cout << std::endl << std::endl;
+  std::cout << "-I- " << myName << ": Set runtime DB" << std::endl;
+  FairRuntimeDb* rtdb      = run->GetRuntimeDb();
+  FairParRootFileIo* parIo = new FairParRootFileIo();
+  parIo->open(parFile.Data(), "UPDATE");
+  rtdb->setFirstInput(parIo);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Run initialisation   -------------------------------------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Initialise run" << std::endl;
+  run->Init();
+  rtdb->setOutput(parIo);
+  rtdb->saveOutput();
+  rtdb->print();
+  // ------------------------------------------------------------------------
+
+
+  // -----   Start run   ----------------------------------------------------
+  std::cout << std::endl << std::endl;
+  std::cout << "-I- " << myName << ": Starting run" << std::endl;
+  run->Run(firstTimeSlice, nTimeSlices);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Finish   -------------------------------------------------------
+  timer.Stop();
+  FairMonitor::GetMonitor()->Print();
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+  std::cout << std::endl << std::endl;
+  std::cout << "Macro finished successfully." << std::endl;
+  std::cout << "Output file is    " << outFile << std::endl;
+  std::cout << "Parameter file is " << parFile << std::endl;
+  std::cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << std::endl;
+  FairSystemInfo sysInfo;
+  Float_t maxMemory = sysInfo.GetMaxMemory();
+  std::cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">";
+  std::cout << maxMemory;
+  std::cout << "</DartMeasurement>" << std::endl;
+  Float_t cpuUsage = ctime / rtime;
+  std::cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">";
+  std::cout << cpuUsage;
+  std::cout << "</DartMeasurement>" << std::endl;
+  // ------------------------------------------------------------------------
+
+
+  // -----   This is to prevent a malloc error when exiting ROOT   ----------
+  // The source of the error is unknown. Related to TGeoManager.
+  RemoveGeoManager();
+  // ------------------------------------------------------------------------
+
+}  // End of main macro function
diff --git a/macro/run/CMakeLists.txt b/macro/run/CMakeLists.txt
index f5ad10da585bcdfedd28d78c75eb5b664c7b4444..4823c6ec629aa57d88385d17783712e2845942b5 100644
--- a/macro/run/CMakeLists.txt
+++ b/macro/run/CMakeLists.txt
@@ -49,7 +49,7 @@ add_test(run_cleanup ${CMAKE_COMMAND}
 	-P ${CMAKE_SOURCE_DIR}/cmake/scripts/cleanmacrodir.cmake)
 set_tests_properties(run_cleanup PROPERTIES
 	TIMEOUT ${timeOutTime}
-	FIXTURES_SETUP cleanup
+	FIXTURES_SETUP run_cleanup
 )
 # ============================================================================
 
@@ -79,7 +79,7 @@ foreach(setup IN LISTS cbm_setup)
   set_tests_properties(${testname} PROPERTIES
   	TIMEOUT ${timeOutTime}
   	PASS_REGULAR_EXPRESSION "Macro finished successfully"
-  	FIXTURES_REQUIRED cleanup
+  	FIXTURES_REQUIRED run_cleanup
   	FIXTURES_SETUP fixt_tra_json_config
   	RESOURCE_LOCK json_config_ParDb
   )
@@ -119,7 +119,7 @@ foreach(setup IN LISTS cbm_setup)
   set_tests_properties(${testname} PROPERTIES
   	TIMEOUT ${timeOutTime}
   	PASS_REGULAR_EXPRESSION "Macro finished successfully"
-  	FIXTURES_REQUIRED cleanup
+  	FIXTURES_REQUIRED run_cleanup
   	FIXTURES_SETUP fixt_tra_sign_${setup}
   	RESOURCE_LOCK signParDb_${setup}
   )
@@ -132,7 +132,7 @@ foreach(setup IN LISTS cbm_setup)
   set_tests_properties(${testname} PROPERTIES
   	TIMEOUT ${timeOutTime}
   	PASS_REGULAR_EXPRESSION "Macro finished successfully"
-  	FIXTURES_REQUIRED cleanup
+  	FIXTURES_REQUIRED run_cleanup
   	FIXTURES_SETUP fixt_tra_beam_${setup}
   	RESOURCE_LOCK beamParDb_${setup}
   )
diff --git a/reco/CMakeLists.txt b/reco/CMakeLists.txt
index 68dcb85e80b53185df1137bf70a409656ca720b6..51754b710c8ea438c15f8875a585bc0524b710fe 100644
--- a/reco/CMakeLists.txt
+++ b/reco/CMakeLists.txt
@@ -12,3 +12,6 @@ add_subdirectory(littrack)
 add_subdirectory(steer)
 add_subdirectory(tracking)
 add_subdirectory(qa)
+if (${CMAKE_CXX_STANDARD} EQUAL 17)
+  add_subdirectory (tasks)
+endif()
diff --git a/reco/tasks/CMakeLists.txt b/reco/tasks/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..310215ee90e1b7ec92168ca47fb04a26e9bbe266
--- /dev/null
+++ b/reco/tasks/CMakeLists.txt
@@ -0,0 +1,71 @@
+# CMakeList file for library libCbmRecoTasks
+# V. Friese,     2 June 2021
+
+
+
+# -----   Library name   ----------------------------------
+Set(LIBRARY_NAME CbmRecoTasks)
+# ---------------------------------------------------------
+
+# -----  Compilation sources   ----------------------------
+set(SRCS
+CbmTaskBuildEvents.cxx
+)
+# ---------------------------------------------------------
+
+
+
+# ----  Include directories -------------------------------
+set(INCLUDE_DIRECTORIES
+${CMAKE_CURRENT_SOURCE_DIR}
+
+${CBMROOT_SOURCE_DIR}/core/base
+${CBMROOT_SOURCE_DIR}/core/data
+${CBMROOT_SOURCE_DIR}/core/data/base
+${CBMROOT_SOURCE_DIR}/core/data/global
+${CBMROOT_SOURCE_DIR}/core/data/sts
+
+${CBMROOT_SOURCE_DIR}/algo/evbuild
+
+)
+
+set(SYSTEM_INCLUDE_DIRECTORIES
+${BASE_INCLUDE_DIRECTORIES}
+${IPC_INCLUDE_DIRECTORY}
+)
+# ---------------------------------------------------------
+
+
+
+# ----  Link directories ----------------------------------
+set(LINK_DIRECTORIES
+${FAIRROOT_LIBRARY_DIR}
+${ROOT_LIBRARY_DIR}
+${Boost_LIBRARY_DIRS}
+)
+# ---------------------------------------------------------
+
+
+
+# -----   Library dependences   ---------------------------
+Set(DEPENDENCIES
+fles_ipc
+Base
+CbmBase
+CbmData
+Algo
+)
+# ---------------------------------------------------------
+
+
+# -----  LinkDef file   -----------------------------------
+set(LINKDEF ${LIBRARY_NAME}LinkDef.h)
+# ---------------------------------------------------------
+
+
+# -----  Let cmake do the job   ---------------------------
+include_directories( ${INCLUDE_DIRECTORIES})
+include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
+link_directories( ${LINK_DIRECTORIES})
+GENERATE_LIBRARY()
+# ---------------------------------------------------------
diff --git a/reco/tasks/CbmRecoTasksLinkDef.h b/reco/tasks/CbmRecoTasksLinkDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..8decde767c8703b2470edaf8eb8fd567fe2cd3af
--- /dev/null
+++ b/reco/tasks/CbmRecoTasksLinkDef.h
@@ -0,0 +1,16 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+// ===== LinkDef for reco/task =====
+
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+// --- Classes
+#pragma link C++ class CbmTaskBuildEvents + ;
+
+#endif /* __CINT__ */
diff --git a/reco/tasks/CbmTaskBuildEvents.cxx b/reco/tasks/CbmTaskBuildEvents.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f5d3aa7a7f3c4f03d938620044888d86f3c58139
--- /dev/null
+++ b/reco/tasks/CbmTaskBuildEvents.cxx
@@ -0,0 +1,170 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+
+#include "CbmTaskBuildEvents.h"
+
+#include "CbmDefs.h"
+#include "CbmDigiBranchBase.h"
+#include "CbmDigiEvent.h"
+#include "CbmDigiManager.h"
+#include "CbmDigiTimeslice.h"
+
+#include <FairLogger.h>
+
+#include <TStopwatch.h>
+
+#include <cassert>
+#include <iomanip>
+#include <iostream>
+#include <vector>
+
+#include "EventBuilder.h"
+
+
+using namespace std;
+
+
+// -----   Constructor   -----------------------------------------------------
+CbmTaskBuildEvents::CbmTaskBuildEvents() : FairTask("BuildEvents") {}
+// ---------------------------------------------------------------------------
+
+
+// -----   Destructor   ------------------------------------------------------
+CbmTaskBuildEvents::~CbmTaskBuildEvents()
+{
+  if (fEvents) delete fEvents;
+}
+// ---------------------------------------------------------------------------
+
+
+// -----   Execution   -------------------------------------------------------
+void CbmTaskBuildEvents::Exec(Option_t*)
+{
+
+  // --- Timer and counters
+  TStopwatch timerStep;
+  TStopwatch timerTot;
+  timerTot.Start();
+
+  // --- Clear output vector
+  fEvents->clear();
+
+  // --- Construct a DigiTimeslice from the data in CbmDigiManager
+  timerStep.Start();
+  CbmDigiTimeslice ts;
+  CbmDigiBranchBase* stsBranch      = fDigiMan->GetBranch(ECbmModuleId::kSts);
+  const vector<CbmStsDigi>* digiVec = boost::any_cast<const vector<CbmStsDigi>*>(stsBranch->GetBranchContainer());
+  assert(digiVec);
+  ts.fData.fSts.fDigis = *digiVec;
+  timerStep.Stop();
+  fTimeFillTs += timerStep.RealTime();
+
+  // --- Construct an artificial trigger list (just preliminary)
+  vector<double> triggerVec {1000., 2000., 3000.};
+
+  // --- Call event builder algorithm
+  timerStep.Start();
+  *fEvents = fAlgo(ts, triggerVec);
+  timerStep.Stop();
+  fTimeBuildEvt += timerStep.RealTime();
+
+  // --- Timeslice statistics
+  size_t numTriggers   = triggerVec.size();
+  size_t numEvents     = fEvents->size();
+  size_t numDigisStsTs = ts.fData.fSts.fDigis.size();
+  size_t numDigisStsEv = 0;
+  for (auto& event : (*fEvents))
+    numDigisStsEv += event.fData.fSts.fDigis.size();
+
+  // --- Timeslice log
+  timerTot.Stop();
+  fTimeTot += timerTot.RealTime();
+  stringstream logOut;
+  logOut << setw(20) << left << GetName() << " [";
+  logOut << fixed << setw(8) << setprecision(1) << right << timerTot.RealTime() * 1000. << " ms] ";
+  logOut << "TS " << fNumTs << ", triggers " << numTriggers << ", events " << numEvents;
+  logOut << ", frac digis " << 100. * double(numDigisStsEv) / double(numDigisStsTs) << " %";
+  LOG(info) << logOut.str();
+
+  // --- Run statistics
+  fNumTs++;
+  fNumTriggers += numTriggers;
+  fNumEvents += numEvents;
+  fNumDigisStsTs += numDigisStsTs;
+  fNumDigisStsEv += numDigisStsEv;
+}
+// ----------------------------------------------------------------------------
+
+
+// -----   End-of-timeslice action   ------------------------------------------
+void CbmTaskBuildEvents::Finish()
+{
+
+  std::cout << std::endl;
+  LOG(info) << "=====================================";
+  LOG(info) << GetName() << ": Run summary";
+  LOG(info) << "Timeslices         : " << fNumTs;
+  LOG(info) << "Triggers           : " << fNumTriggers;
+  LOG(info) << "Events             : " << fNumEvents;
+  LOG(info) << "Digis in timeslice : " << fNumDigisStsTs;
+  LOG(info) << "Digis in events    : " << fNumDigisStsEv << " = " << fixed << setprecision(2)
+            << 100. * double(fNumDigisStsEv) / double(fNumDigisStsTs) << " %";
+  LOG(info) << "Time  / TS         : " << fixed << setprecision(2) << 1000. * fTimeTot / double(fNumTs) << " ms";
+  LOG(info) << "Time fill TS       : " << fixed << setprecision(2) << 1000. * fTimeFillTs / double(fNumTs)
+            << " ms = " << 100. * fTimeFillTs / fTimeTot << " %";
+  LOG(info) << "Time build events  : " << fixed << setprecision(2) << 1000. * fTimeBuildEvt / double(fNumTs)
+            << " ms = " << 100. * fTimeBuildEvt / fTimeTot << " %";
+  LOG(info) << "=====================================";
+}
+// ----------------------------------------------------------------------------
+
+
+// -----   Initialisation   ---------------------------------------------------
+InitStatus CbmTaskBuildEvents::Init()
+{
+
+  // --- Get FairRootManager instance
+  FairRootManager* ioman = FairRootManager::Instance();
+  assert(ioman);
+
+  // --- DigiManager instance
+  fDigiMan = CbmDigiManager::Instance();
+  fDigiMan->Init();
+
+  std::cout << std::endl;
+  LOG(info) << "==================================================";
+  LOG(info) << GetName() << ": Initialising...";
+
+
+  // --- Check input data (STS only for the time being)
+  if (!fDigiMan->IsPresent(ECbmModuleId::kSts)) {
+    LOG(fatal) << GetName() << ": No digi branch for STS";
+    return kFATAL;
+  }
+
+  // --- Register output array (CbmDigiEvent)
+  if (ioman->GetObject("DigiEvent")) {
+    LOG(fatal) << GetName() << ": Branch DigiEvent already exists!";
+    return kFATAL;
+  }
+  fEvents = new vector<CbmDigiEvent>;
+  ioman->RegisterAny("DigiEvent", fEvents, IsOutputBranchPersistent("DigiEvent"));
+  if (!fEvents) {
+    LOG(fatal) << GetName() << ": Output branch could not be created!";
+    return kFATAL;
+  }
+
+  // --- Configure algorithm
+  fAlgo.SetTriggerWindow(ECbmModuleId::kSts, fEvtTimeStsMin, fEvtTimeStsMax);
+
+
+  LOG(info) << "==================================================";
+  std::cout << std::endl;
+
+  return kSUCCESS;
+}
+// ----------------------------------------------------------------------------
+
+ClassImp(CbmTaskBuildEvents)
diff --git a/reco/tasks/CbmTaskBuildEvents.h b/reco/tasks/CbmTaskBuildEvents.h
new file mode 100644
index 0000000000000000000000000000000000000000..8e7e588de436979dd83cf6eb34f2818840fbdb62
--- /dev/null
+++ b/reco/tasks/CbmTaskBuildEvents.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+
+#ifndef CBMTASKBUILDEVENTS_H
+#define CBMTASKBUILDEVENTS_H 1
+
+
+#include "CbmDefs.h"
+#include "CbmDigiEvent.h"
+
+#include <FairTask.h>
+
+#include <vector>
+
+#include "EventBuilder.h"
+
+class CbmDigiManager;
+
+
+/** @class CbmTaskBuildEvents
+ ** @brief Task class for associating digis to events
+ ** @author Volker Friese <v.friese@gsi.de>
+ ** @since 15.11.2021
+ **
+ ** Creates objects of class CbmDigiEvent and fills them with digi objects,
+ ** using the algorithm EventBuilder.
+ **
+ ** TOFO: The current implementation is for STS only and with a dummy trigger list
+ ** just to establish the framework integration of algorithm and data interfaces.
+ **/
+class CbmTaskBuildEvents : public FairTask {
+
+
+public:
+  /** @brief Constructor **/
+  CbmTaskBuildEvents();
+
+
+  /** @brief Copy constructor (disabled) **/
+  CbmTaskBuildEvents(const CbmTaskBuildEvents&) = delete;
+
+
+  /** @brief Destructor **/
+  virtual ~CbmTaskBuildEvents();
+
+
+  /** @brief Task execution **/
+  virtual void Exec(Option_t* opt);
+
+
+  /** @brief Finish timeslice **/
+  virtual void Finish();
+
+
+  /** @brief Assignment operator (disabled) **/
+  CbmTaskBuildEvents& operator=(const CbmTaskBuildEvents&) = delete;
+
+
+  /** @brief Configure the event building time intervals
+   ** @param tMin    Trigger window start time w.r.t. trigger time
+   ** @param tMax    Trigger window end time w.r.t. trigger time
+   **/
+  void SetTimeWindow(double tMin, double tMax)
+  {
+    fEvtTimeStsMin = tMin;
+    fEvtTimeStsMax = tMax;
+  }
+
+
+private:  // methods
+  /** @brief Task initialisation **/
+  virtual InitStatus Init();
+
+
+private:                                         // members
+  CbmDigiManager* fDigiMan = nullptr;            //! Input data
+  std::vector<ECbmModuleId> fSystems {};         //  List of detector systems
+  std::vector<CbmDigiEvent>* fEvents = nullptr;  //! Output data
+  cbm::algo::EventBuilder fAlgo {};              //! Algorithm
+  double fEvtTimeStsMin = 0.;
+  double fEvtTimeStsMax = 0.;
+  size_t fNumTs         = 0;  //  Number of processed time slices
+  size_t fNumTriggers   = 0;  //  Number of triggers
+  size_t fNumEvents     = 0;  //  Number of produced events
+  size_t fNumDigisStsTs = 0;  //  Number of digis in timeslices
+  size_t fNumDigisStsEv = 0;  //  Number of digis in events
+  double fTimeFillTs    = 0.;
+  double fTimeBuildEvt  = 0.;
+  double fTimeTot       = 0.;
+
+
+  ClassDef(CbmTaskBuildEvents, 1);
+};
+
+#endif /* CBMTASKBUILDEVENTS_H */