diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt
index 02b3dbfb8ed21d80deca14d8a9892e4ddf873146..dabaaa06f46dad0bca02e29a42b93df1e26e4c88 100644
--- a/algo/CMakeLists.txt
+++ b/algo/CMakeLists.txt
@@ -13,9 +13,11 @@ set(SRCS
   ${DEVICE_SRCS}
   base/ChainContext.cxx
   base/Options.cxx
+  base/MainConfig.cxx
   base/util/TimingsFormat.cxx
   data/sts/LandauTable.cxx
   evbuild/EventBuilder.cxx
+  evbuild/EventbuildChain.cxx
   trigger/TimeClusterTrigger.cxx
   evselector/DigiEventSelector.cxx
   unpack/Unpack.cxx
@@ -73,7 +75,8 @@ target_include_directories(Algo
          ${CMAKE_CURRENT_SOURCE_DIR}/unpack
          ${CMAKE_CURRENT_SOURCE_DIR}/detectors
          ${CMAKE_CURRENT_SOURCE_DIR}/qa
- )
+         ${CMAKE_SOURCE_DIR}/core/data/global
+)
 
 target_link_libraries(Algo
   PUBLIC    OnlineData
diff --git a/algo/base/MainConfig.cxx b/algo/base/MainConfig.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4039d89f8b6e73503fa7a2d0911999f5c719d134
--- /dev/null
+++ b/algo/base/MainConfig.cxx
@@ -0,0 +1,89 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+#include "MainConfig.h"
+
+#include <fstream>
+
+#include <yaml-cpp/yaml.h>
+
+namespace cbm::algo
+{
+
+  // -----   Load configuration from YAML file   --------------------------------
+  void MainConfig::LoadYaml(const std::string& filename)
+  {
+    YAML::Node config = YAML::LoadFile(filename);
+
+    // --- Digi trigger
+    fTriggerDet       = ToCbmModuleIdCaseInsensitive(config["trigger"]["detector"].as<std::string>());
+    fTriggerWin       = config["trigger"]["window"].as<double>();
+    fTriggerThreshold = config["trigger"]["threshold"].as<size_t>();
+    fTriggerDeadTime  = config["trigger"]["deadtime"].as<double>();
+
+    // --- Event builder: (detector -> (tMin, tMax))
+    if (auto eventbuilder = config["eventbuilder"]) {
+      if (auto windows = eventbuilder["windows"]) {
+        for (YAML::const_iterator it = windows.begin(); it != windows.end(); ++it) {
+          auto det              = ToCbmModuleIdCaseInsensitive(it->first.as<std::string>());
+          auto lower            = it->second[0].as<double>();
+          auto upper            = it->second[1].as<double>();
+          fEvtbuildWindows[det] = std::make_pair(lower, upper);
+        }
+      }
+    }
+
+    // --- Event selector parameters
+    fSelectMinStationsSts = config["selector"]["minStationsSts"].as<size_t>();
+    fSelectMinStationsTof = config["selector"]["minStationsTof"].as<size_t>();
+    fSelectMinDigisBmon   = config["selector"]["minDigisBmon"].as<size_t>();
+
+    // --- Branch persistence in output file
+    fStoreTimeslice = config["store"]["timeslice"].as<bool>();
+    fStoreTrigger   = config["store"]["triggers"].as<bool>();
+    fStoreEvents    = config["store"]["events"].as<bool>();
+
+    // --- QA publishing
+    fHttpServerRefreshRate = config["qa"]["refreshrate"].as<int32_t>(fHttpServerRefreshRate);
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // -----   Save configuration to YAML file   ----------------------------------
+  void MainConfig::SaveYaml(const std::string& filename)
+  {
+    YAML::Node config;
+
+    // --- Digi trigger
+    config["trigger"]["detector"]  = ToString(fTriggerDet);
+    config["trigger"]["window"]    = fTriggerWin;
+    config["trigger"]["threshold"] = fTriggerThreshold;
+    config["trigger"]["deadtime"]  = fTriggerDeadTime;
+
+    // --- Event builder: (detector -> (tMin, tMax))
+    for (const auto& [key, value] : fEvtbuildWindows) {
+      auto det = ToString(key);
+      config["eventbuilder"]["windows"][det].push_back(value.first);
+      config["eventbuilder"]["windows"][det].push_back(value.second);
+    };
+
+    // --- Event selector
+    config["selector"]["minStationsSts"] = fSelectMinStationsSts;
+    config["selector"]["minStationsTof"] = fSelectMinStationsTof;
+    config["selector"]["minDigisBmon"]   = fSelectMinDigisBmon;
+
+
+    // --- Branch persistence in output file
+    config["store"]["timeslice"] = fStoreTimeslice;
+    config["store"]["triggers"]  = fStoreTrigger;
+    config["store"]["events"]    = fStoreEvents;
+    // --- QA publishing
+    config["qa"]["refreshrate"] = fHttpServerRefreshRate;
+    // ---
+    std::ofstream fout(filename);
+    fout << config;
+  }
+  // ----------------------------------------------------------------------------
+
+} /* namespace cbm::algo */
diff --git a/algo/base/MainConfig.h b/algo/base/MainConfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..34a1a13a162dc9856be2379b6f7c87d107262295
--- /dev/null
+++ b/algo/base/MainConfig.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+
+#ifndef ALGO_BASE_MAINCONFIG_H_
+#define ALGO_BASE_MAINCONFIG_H_
+
+#include "CbmDefs.h"
+
+#include <map>
+
+namespace cbm::algo
+{
+
+  /** @class MainConfig
+   ** @brief Configuration of online data processing
+   ** @author Volker Friese <v.friese@gsi.de>
+   ** @since 10 July 2023
+   **/
+  class MainConfig {
+  public:  // methods
+    /** @brief Constructor **/
+    MainConfig() = default;
+
+    /** @brief Constructor **/
+    ~MainConfig() = default;
+
+    /** @brief Load from YAML file **/
+    void LoadYaml(const std::string& filename);
+
+    /** @brief Save to YAML file **/
+    void SaveYaml(const std::string& filename);
+
+  public:  // data members
+    // --- Digi trigger
+    ECbmModuleId fTriggerDet = ECbmModuleId::kNotExist;  // Trigger detector
+    double fTriggerWin       = 0.;                       // Trigger window size [ns]
+    size_t fTriggerThreshold = 0;                        // Minimum number if digis in trigger window
+    double fTriggerDeadTime  = 0.;                       // Minimal time between two trigger [ns]
+
+    // --- Event builder: (detector -> (tMin, tMax))
+    std::map<ECbmModuleId, std::pair<double, double>> fEvtbuildWindows = {};
+
+    // --- Event selector
+    size_t fSelectMinStationsSts = 0;
+    size_t fSelectMinStationsTof = 0;
+    size_t fSelectMinDigisBmon   = 0;
+
+    // --- Branch persistence in output file
+    bool fStoreTimeslice = false;
+    bool fStoreTrigger   = false;
+    bool fStoreEvents    = false;
+
+    // --- QA publishing
+    int32_t fHttpServerRefreshRate = 100;
+  };
+
+} /* namespace cbm::algo */
+
+#endif /* ALGO_BASE_MAINCONFIG_H_ */
diff --git a/algo/evbuild/EventbuildChain.cxx b/algo/evbuild/EventbuildChain.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0b83b9d5a4e97bd3fa6db698fc478b242a6f2354
--- /dev/null
+++ b/algo/evbuild/EventbuildChain.cxx
@@ -0,0 +1,145 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+#include "EventbuildChain.h"
+
+using namespace cbm::algo;
+
+
+// -----   Initialization   ---------------------------------------------------
+void EventbuildChain::Init(const MainConfig& config)
+{
+
+  // TODO: Initialization should be part of the constructor, such that uninitialised objects
+  // cannot be instantiated.
+
+
+  fConfig = config;  // is used also in the Run method
+
+  // --- Configure the event builder
+  for (const auto& entry : fConfig.fEvtbuildWindows) {
+    auto system       = entry.first;
+    const double tMin = entry.second.first;
+    const double tMax = entry.second.second;
+    fEventBuilder.SetEventWindow(system, tMin, tMax);
+    L_(info) << "--- Use algo EventBuilder for " << ToString(system) << " with event window [" << tMin << ", " << tMax
+             << "] ns";
+  }
+
+  // --- Configure the event selector
+  size_t minStatSts   = fConfig.fSelectMinStationsSts;
+  size_t minStatTof   = fConfig.fSelectMinStationsTof;
+  size_t minDigisBmon = fConfig.fSelectMinDigisBmon;
+  auto selectPar      = cbm::algo::DigiEventSelectorParams {minStatSts, minStatTof, minDigisBmon};
+  fSelector.SetParams(selectPar);
+
+  // --- Configure the event QA
+  const double border    = 10.;  // TODO: Histogram border hard-coded
+  const uint32_t numBins = 100;  // TODO: Histogram bin number hard-coded
+  for (const auto& entry : config.fEvtbuildWindows) {
+    ECbmModuleId system     = entry.first;
+    double lower            = entry.second.first - border;   // Lower edge of histogram
+    double upper            = entry.second.second + border;  // Upper edge of histogram
+    fQaConfig.fData[system] = {numBins, lower, upper};
+  }
+
+  // N.b. The trigger algorithm need not be configured; its parameters are passed with each
+  // execution call.
+}
+// ----------------------------------------------------------------------------
+
+
+// -----   Run event building on a timeslice   --------------------------------
+std::vector<CbmDigiEvent> EventbuildChain::Run(const CbmDigiTimeslice& timeslice)
+{
+
+  // --- Extract the digi time stamps of the trigger detector
+  std::vector<double> digiTimes = GetDigiTimes(timeslice, fConfig.fTriggerDet);
+
+  // --- Call the trigger algorithm
+  std::vector<double> triggers =
+    fTrigger(digiTimes, fConfig.fTriggerWin, fConfig.fTriggerThreshold, fConfig.fTriggerDeadTime).first;
+
+  // --- Perform event building
+  std::vector<CbmDigiEvent> events = fEventBuilder(timeslice, triggers).first;
+
+  // --- Apply event selector
+  auto notSelected = [&](CbmDigiEvent& ev) { return !fSelector(ev); };
+  auto removeIt    = std::remove_if(events.begin(), events.end(), notSelected);
+  events.erase(removeIt, events.end());
+
+  // --- Run event QA
+  qa::DigiEventQaData qaData = fQa(events, fQaConfig);
+
+  // --- Some log
+  L_(info) << "Triggers: " << triggers.size() << ", events " << events.size();
+
+  return events;
+}
+// ----------------------------------------------------------------------------
+
+
+// -----   Get digi times from CbmDigiTimeslice   -----------------------------
+std::vector<double> EventbuildChain::GetDigiTimes(const CbmDigiTimeslice& timeslice, ECbmModuleId system)
+{
+  std::vector<double> result;
+  switch (system) {
+    case ECbmModuleId::kSts: {
+      result.resize(timeslice.fData.fSts.fDigis.size());
+      auto it1 = timeslice.fData.fSts.fDigis.begin();
+      auto it2 = timeslice.fData.fSts.fDigis.end();
+      std::transform(it1, it2, result.begin(), [](const CbmStsDigi& digi) { return digi.GetTime(); });
+      break;
+    }
+    case ECbmModuleId::kRich: {
+      result.resize(timeslice.fData.fRich.fDigis.size());
+      auto it1 = timeslice.fData.fRich.fDigis.begin();
+      auto it2 = timeslice.fData.fRich.fDigis.end();
+      std::transform(it1, it2, result.begin(), [](const CbmRichDigi& digi) { return digi.GetTime(); });
+      break;
+    }
+    case ECbmModuleId::kMuch: {
+      result.resize(timeslice.fData.fMuch.fDigis.size());
+      auto it1 = timeslice.fData.fMuch.fDigis.begin();
+      auto it2 = timeslice.fData.fMuch.fDigis.end();
+      std::transform(it1, it2, result.begin(), [](const CbmMuchDigi& digi) { return digi.GetTime(); });
+      break;
+    }
+    case ECbmModuleId::kTrd: {
+      result.resize(timeslice.fData.fTrd.fDigis.size());
+      auto it1 = timeslice.fData.fTrd.fDigis.begin();
+      auto it2 = timeslice.fData.fTrd.fDigis.end();
+      std::transform(it1, it2, result.begin(), [](const CbmTrdDigi& digi) { return digi.GetTime(); });
+      break;
+    }
+    case ECbmModuleId::kTof: {
+      result.resize(timeslice.fData.fTof.fDigis.size());
+      auto it1 = timeslice.fData.fTof.fDigis.begin();
+      auto it2 = timeslice.fData.fTof.fDigis.end();
+      std::transform(it1, it2, result.begin(), [](const CbmTofDigi& digi) { return digi.GetTime(); });
+      break;
+    }
+    case ECbmModuleId::kPsd: {
+      result.resize(timeslice.fData.fPsd.fDigis.size());
+      auto it1 = timeslice.fData.fPsd.fDigis.begin();
+      auto it2 = timeslice.fData.fPsd.fDigis.end();
+      std::transform(it1, it2, result.begin(), [](const CbmPsdDigi& digi) { return digi.GetTime(); });
+      break;
+    }
+    case ECbmModuleId::kT0: {
+      result.resize(timeslice.fData.fT0.fDigis.size());
+      auto it1 = timeslice.fData.fT0.fDigis.begin();
+      auto it2 = timeslice.fData.fT0.fDigis.end();
+      std::transform(it1, it2, result.begin(), [](const CbmTofDigi& digi) { return digi.GetTime(); });
+      break;
+    }
+    default: {
+      L_(error) << "EventbuildChain::GetDigiTimes: Unknown system " << system;
+      break;
+    }
+  }  //? system
+
+  return result;
+}
+// ----------------------------------------------------------------------------
diff --git a/algo/evbuild/EventbuildChain.h b/algo/evbuild/EventbuildChain.h
new file mode 100644
index 0000000000000000000000000000000000000000..b45094c2b4cbe481ea59319aaa42ecd215770bdd
--- /dev/null
+++ b/algo/evbuild/EventbuildChain.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Volker Friese [committer] */
+
+#ifndef CBM_ALGO_EVBUILD_EVBUILDCHAIN_H
+#define CBM_ALGO_EVBUILD_EVBUILDCHAIN_H 1
+
+#include "CbmDefs.h"
+#include "CbmDigiTimeslice.h"
+
+#include "TimeClusterTrigger.h"
+
+#include "DigiEventQa.h"
+#include "DigiEventSelector.h"
+#include "EventBuilder.h"
+#include "MainConfig.h"
+#include "SubChain.h"
+
+namespace cbm::algo
+{
+
+  /** @class EventbuildChain
+   ** @brief Steering class for event building from digi timeslices
+   ** @author Volker Friese <v.friese@gsi.de>
+   ** @since 11 July 2023
+   **
+   ** Constructs a vector of CbmDigiEvents from a CbmDigiTimeslice. Uses the algorithms
+   ** - TimeClusterTrigger for the event time definiton
+   ** - EventBuilder for construction of events by time intervals around the trigger time
+   ** - DigiEventSelector for selection of constructed events according to the specified criteria
+   **/
+  class EventbuildChain : public SubChain {
+
+  public:
+    /** @brief Initialization **/
+    void Init(const MainConfig& config);
+
+    /** @brief Execution **/
+    std::vector<CbmDigiEvent> Run(const CbmDigiTimeslice&);
+
+
+  private:                            // members
+    MainConfig fConfig;               ///< Configuration / parameters
+    TimeClusterTrigger fTrigger;      ///< Trigger algorithm
+    EventBuilder fEventBuilder;       ///< Event builder algorithm
+    DigiEventSelector fSelector;      ///< Event selector algorithm
+    qa::DigiEventQa fQa;              ///< Event QA algorithm
+    qa::DigiEventQaConfig fQaConfig;  ///< Configuration for event QA
+
+
+  private:  // methods
+    /** @brief Extract digi times from CbmDigiTimeslice
+     ** @param system Detector system (enum ECbmModuleId)
+     ** @return Vector of digi times for the specified system
+     **/
+    std::vector<double> GetDigiTimes(const CbmDigiTimeslice& timeslice, ECbmModuleId system);
+  };
+
+}  // namespace cbm::algo
+
+
+#endif  //CBM_ALGO_EVBUILD_EVBUILDCHAIN
diff --git a/algo/evselector/DigiEventSelector.h b/algo/evselector/DigiEventSelector.h
index 119dda5955f1d937243ba415adae2aad0d1736eb..2a1f4e10b1651af8a6fbd25d02f881bdbf87cb1c 100644
--- a/algo/evselector/DigiEventSelector.h
+++ b/algo/evselector/DigiEventSelector.h
@@ -30,6 +30,7 @@ namespace cbm::algo
   class DigiEventSelector {
 
   public:
+    DigiEventSelector() {};
     DigiEventSelector(DigiEventSelectorParams params) { fParams = params; }
     bool operator()(const CbmDigiEvent& event) const;
 
diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx
index c485b03a876a2a7bb3b2f215f4dabaf1ad406b82..a15bc7fd268c2e0fc7ba40fbf2c0ce7c33237efe 100644
--- a/algo/global/Reco.cxx
+++ b/algo/global/Reco.cxx
@@ -10,6 +10,7 @@
 
 #include <xpu/host.h>
 
+#include "MainConfig.h"
 #include "config/Yaml.h"
 #include "log.hpp"
 #include "util/TimingsFormat.h"
@@ -59,9 +60,17 @@ void Reco::Init(const Options& opts)
   YAML::Node yaml         = YAML::LoadFile(recoParamsPath.string());
   fContext.recoParams     = config::Read<RecoParams>(yaml);
 
+  // --- Main configuration
+  fs::path configFile = opts.ParamsDir() / "config.yaml";
+  MainConfig config;
+  config.LoadYaml(configFile.string());
+
   // Unpackers
   fUnpack.Init();
 
+  // --- Event building
+  fEventBuild.Init(config);
+
   // STS Hitfinder
   fs::path stsHitfinderParamsPath    = opts.ParamsDir() / "StsHitfinder.yaml";
   yaml                               = YAML::LoadFile(stsHitfinderParamsPath.string());
@@ -99,6 +108,12 @@ RecoResults Reco::Run(const fles::Timeslice& ts)
       case RecoParams::UnpackMode::CPU: digiTs = fUnpack.Run(ts).first; break;
     }
   }
+
+  // --- Digi event building
+  std::vector<CbmDigiEvent> events;
+  if (Opts().HasStep(Step::DigiTrigger)) events = fEventBuild.Run(digiTs);
+
+
   if (Opts().HasStep(Step::LocalReco) && Opts().HasDetector(fles::Subsystem::STS))
     fStsHitFinder(digiTs.fData.fSts.fDigis);
 
diff --git a/algo/global/Reco.h b/algo/global/Reco.h
index ff2eae07287b7270c39d38f99e2a7ff5eaf74c83..2eef46610da84fcfca7c410dc62897925d114a9f 100644
--- a/algo/global/Reco.h
+++ b/algo/global/Reco.h
@@ -6,6 +6,7 @@
 
 #include <xpu/host.h>
 
+#include "EventbuildChain.h"
 #include "RecoResults.h"
 #include "SubChain.h"
 #include "UnpackChain.h"
@@ -44,6 +45,8 @@ namespace cbm::algo
     UnpackChain fUnpack;
     sts::HitfinderChain fStsHitFinder;
 
+    EventbuildChain fEventBuild;
+
     void Validate(const Options& opts);
   };
 }  // namespace cbm::algo
diff --git a/algo/params/config.yaml b/algo/params/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..677b1bf105bcfdb56691cf5290df3c08dfeeb794
--- /dev/null
+++ b/algo/params/config.yaml
@@ -0,0 +1,24 @@
+trigger:
+  detector: TOF
+  window: 80
+  threshold: 8
+  deadtime: 50
+eventbuilder:
+  windows:
+    T0:    [-65, 65]
+    STS:   [-75, 75]
+    MUCH:  [-50, 500]
+    TRD :  [-100, 300]
+    TRd2D: [-100, 350]
+    TOF:   [-10, 70]
+    RICH:  [-20, 120]
+selector:
+    minStationsSts: 0
+    minStationsTof: 0
+    minDigisBmon: 1
+store:
+  timeslice: false
+  triggers: false
+  events: true
+qa:
+  refreshrate: 100
diff --git a/macro/reco/reco_fairroot.C b/macro/reco/reco_fairroot.C
index 9e9508c3ac69ead7fa3159e9336504d2fb1745f2..b693b3a18ce5801e3264c716fa89526a1485ed3a 100644
--- a/macro/reco/reco_fairroot.C
+++ b/macro/reco/reco_fairroot.C
@@ -50,7 +50,7 @@ void reco_fairroot(TString tsaFile, TString outFile, int32_t numTs = std::numeri
 
   // --- Configuration  -----------------------------------------------------
   // Digi trigger
-  CbmRecoConfig config;
+  cbm::algo::MainConfig config;
   config.fTriggerDet       = ECbmModuleId::kSts;  // trigger detector
   config.fTriggerWin       = 10.;                 // trigger window in [ns]
   config.fTriggerThreshold = 100;                 // trigger threshold in number of digis
diff --git a/reco/app/cbmreco_fairrun/Application.cxx b/reco/app/cbmreco_fairrun/Application.cxx
index eb4cc41101c5bacd1f17939250a0bda57db02c2d..9979a9a10b6db43c1e0e3579d16147424ff61572 100644
--- a/reco/app/cbmreco_fairrun/Application.cxx
+++ b/reco/app/cbmreco_fairrun/Application.cxx
@@ -7,12 +7,14 @@
 #include <chrono>
 #include <thread>
 
+#include "MainConfig.h"
+
 Application::Application(ProgramOptions const& opt) : fOpt(opt)
 {
   // start up monitoring
   if (!fOpt.MonitorUri().empty()) { fMonitor = std::make_unique<cbm::Monitor>(fOpt.MonitorUri()); }
 
-  CbmRecoConfig config;
+  cbm::algo::MainConfig config;
   config.LoadYaml(fOpt.ConfigYamlFile());
   if (!fOpt.SaveConfigYamlFile().empty()) { config.SaveYaml(fOpt.SaveConfigYamlFile()); }
 
diff --git a/reco/tasks/CbmReco.cxx b/reco/tasks/CbmReco.cxx
index 8be25218f2688651f96707478ab5df68a49b9011..32d1b020702878b1718aaaaddcbf05a1b85c3724 100644
--- a/reco/tasks/CbmReco.cxx
+++ b/reco/tasks/CbmReco.cxx
@@ -23,92 +23,14 @@
 #include <memory>
 #include <string>
 
-#include <yaml-cpp/yaml.h>
-
 #include "DigiEventSelector.h"
 
 using std::make_unique;
 using std::string;
 
 
-// -----   Load configuration from YAML file   --------------------------------
-void CbmRecoConfig::LoadYaml(const std::string& filename)
-{
-  YAML::Node config = YAML::LoadFile(filename);
-
-  // --- Digi trigger
-  fTriggerDet       = ToCbmModuleIdCaseInsensitive(config["trigger"]["detector"].as<std::string>());
-  fTriggerWin       = config["trigger"]["window"].as<double>();
-  fTriggerThreshold = config["trigger"]["threshold"].as<size_t>();
-  fTriggerDeadTime  = config["trigger"]["deadtime"].as<double>();
-
-  // --- Event builder: (detector -> (tMin, tMax))
-  if (auto eventbuilder = config["eventbuilder"]) {
-    if (auto windows = eventbuilder["windows"]) {
-      for (YAML::const_iterator it = windows.begin(); it != windows.end(); ++it) {
-        auto det              = ToCbmModuleIdCaseInsensitive(it->first.as<std::string>());
-        auto lower            = it->second[0].as<double>();
-        auto upper            = it->second[1].as<double>();
-        fEvtbuildWindows[det] = std::make_pair(lower, upper);
-      }
-    }
-  }
-
-  // --- Event selector parameters
-  fSelectMinStationsSts = config["selector"]["minStationsSts"].as<size_t>();
-  fSelectMinStationsTof = config["selector"]["minStationsTof"].as<size_t>();
-  fSelectMinDigisBmon   = config["selector"]["minDigisBmon"].as<size_t>();
-
-  // --- Branch persistence in output file
-  fStoreTimeslice = config["store"]["timeslice"].as<bool>();
-  fStoreTrigger   = config["store"]["triggers"].as<bool>();
-  fStoreEvents    = config["store"]["events"].as<bool>();
-
-  // --- QA publishing
-  fHttpServerRefreshRate = config["qa"]["refreshrate"].as<int32_t>(fHttpServerRefreshRate);
-}
-// ----------------------------------------------------------------------------
-
-
-// -----   Save configuration to YAML file   ----------------------------------
-void CbmRecoConfig::SaveYaml(const std::string& filename)
-{
-  YAML::Node config;
-
-  // --- Digi trigger
-  config["trigger"]["detector"]  = ToString(fTriggerDet);
-  config["trigger"]["window"]    = fTriggerWin;
-  config["trigger"]["threshold"] = fTriggerThreshold;
-  config["trigger"]["deadtime"]  = fTriggerDeadTime;
-
-  // --- Event builder: (detector -> (tMin, tMax))
-  for (const auto& [key, value] : fEvtbuildWindows) {
-    auto det = ToString(key);
-    config["eventbuilder"]["windows"][det].push_back(value.first);
-    config["eventbuilder"]["windows"][det].push_back(value.second);
-  };
-
-  // --- Event selector
-  config["selector"]["minStationsSts"] = fSelectMinStationsSts;
-  config["selector"]["minStationsTof"] = fSelectMinStationsTof;
-  config["selector"]["minDigisBmon"]   = fSelectMinDigisBmon;
-
-
-  // --- Branch persistence in output file
-  config["store"]["timeslice"] = fStoreTimeslice;
-  config["store"]["triggers"]  = fStoreTrigger;
-  config["store"]["events"]    = fStoreEvents;
-  // --- QA publishing
-  config["qa"]["refreshrate"] = fHttpServerRefreshRate;
-  // ---
-  std::ofstream fout(filename);
-  fout << config;
-}
-// ----------------------------------------------------------------------------
-
-
 // -----   Constructor from single source   -----------------------------------
-CbmReco::CbmReco(string source, TString outFile, int32_t numTs, const CbmRecoConfig& config, uint16_t port,
+CbmReco::CbmReco(string source, TString outFile, int32_t numTs, const cbm::algo::MainConfig& config, uint16_t port,
                  cbm::Monitor* monitor)
   : fSourceNames {source}
   , fOutputFileName(outFile)
@@ -122,7 +44,7 @@ CbmReco::CbmReco(string source, TString outFile, int32_t numTs, const CbmRecoCon
 
 
 // -----   Constructor from multiple sources   --------------------------------
-CbmReco::CbmReco(std::vector<string> sources, TString outFile, int32_t numTs, const CbmRecoConfig& config,
+CbmReco::CbmReco(std::vector<string> sources, TString outFile, int32_t numTs, const cbm::algo::MainConfig& config,
                  uint16_t port, cbm::Monitor* monitor)
   : fSourceNames(sources)
   , fOutputFileName(outFile)
diff --git a/reco/tasks/CbmReco.h b/reco/tasks/CbmReco.h
index 3b82f88cadc4cc6f6e20471537afdbd21a2d87ab..112095846db7ab49602293b770c2db77634ba9c0 100644
--- a/reco/tasks/CbmReco.h
+++ b/reco/tasks/CbmReco.h
@@ -25,39 +25,7 @@ namespace cbm
 #include <string>
 #include <utility>
 
-
-/** @class CbmRecoConfig
- ** @brief Configuration of reconstruction
- ** @author Volker Friese <v.friese@gsi.de>
- ** @since 14 March 2022
- **/
-class CbmRecoConfig {
-public:
-  // --- Digi trigger
-  ECbmModuleId fTriggerDet = ECbmModuleId::kNotExist;  // Trigger detector
-  double fTriggerWin       = 0.;                       // Trigger window size [ns]
-  size_t fTriggerThreshold = 0;                        // Minimum number if digis in trigger window
-  double fTriggerDeadTime  = 0.;                       // Minimal time between two trigger [ns]
-  // --- Event builder: (detector -> (tMin, tMax))
-  std::map<ECbmModuleId, std::pair<double, double>> fEvtbuildWindows = {};
-  // --- Event selector
-  size_t fSelectMinStationsSts = 0;
-  size_t fSelectMinStationsTof = 0;
-  size_t fSelectMinDigisBmon   = 0;
-  // --- Branch persistence in output file
-  bool fStoreTimeslice = false;
-  bool fStoreTrigger   = false;
-  bool fStoreEvents    = false;
-  // --- QA publishing
-  int32_t fHttpServerRefreshRate = 100;
-  // --- Load/save using yaml-cpp
-  void LoadYaml(const std::string& filename);
-  void SaveYaml(const std::string& filename);
-  // --- Destructor
-  virtual ~CbmRecoConfig() {};
-
-  ClassDef(CbmRecoConfig, 1);
-};
+#include "MainConfig.h"
 
 
 /** @class CbmReco
@@ -87,7 +55,7 @@ public:
    ** @param config  Configuration
    ** @param port    Port number for the http server. If 0, server will not be activated.
    **/
-  CbmReco(std::string source, TString outFile, int32_t numTs, const CbmRecoConfig& config, uint16_t port = 0,
+  CbmReco(std::string source, TString outFile, int32_t numTs, const cbm::algo::MainConfig& config, uint16_t port = 0,
           cbm::Monitor* monitor = nullptr);
 
 
@@ -98,7 +66,7 @@ public:
    ** @param config  Configuration
    ** @param port    Port number for the http server
    **/
-  CbmReco(std::vector<std::string> sources, TString outFile, int32_t numTs, const CbmRecoConfig& config,
+  CbmReco(std::vector<std::string> sources, TString outFile, int32_t numTs, const cbm::algo::MainConfig& config,
           uint16_t port = 0, cbm::Monitor* monitor = nullptr);
 
 
@@ -122,7 +90,7 @@ private:
   std::vector<std::string> fSourceNames = {};  ///< Sources (input files or stream)
   TString fOutputFileName               = "";  ///< Output file
   int32_t fNumTs                        = 0;   ///< Number of timeslices to process
-  CbmRecoConfig fConfig                 = {};  ///< Configuration parameters
+  cbm::algo::MainConfig fConfig         = {};  ///< Configuration
   uint16_t fHttpServerPort              = 0;
   cbm::Monitor* fMonitor                = nullptr;
 
diff --git a/reco/tasks/CbmRecoTasksLinkDef.h b/reco/tasks/CbmRecoTasksLinkDef.h
index 590d0cfb5f33f5ba4282f9b650b28cc37fb2e3dd..16e011359c06c17317bcf9b373304d58bec362f6 100644
--- a/reco/tasks/CbmRecoTasksLinkDef.h
+++ b/reco/tasks/CbmRecoTasksLinkDef.h
@@ -12,7 +12,6 @@
 
 // --- Classes
 #pragma link C++ class CbmReco + ;
-#pragma link C++ class CbmRecoConfig + ;
 #pragma link C++ class CbmSourceTs + ;
 #pragma link C++ class CbmTaskBuildEvents + ;
 #pragma link C++ class CbmTaskDigiEventQa + ;
@@ -22,6 +21,7 @@
 #pragma link C++ class CbmTaskTriggerDigi + ;
 #pragma link C++ class CbmTaskUnpack + ;
 #pragma link C++ class CbmTaskUnpackXpu + ;
+#pragma link C++ class cbm::algo::MainConfig + ;
 
 
 #endif /* __CINT__ */
diff --git a/reco/tasks/CbmTaskDigiEventQa.cxx b/reco/tasks/CbmTaskDigiEventQa.cxx
index 87fe026458cdd97f222bca310a78ff7543487d60..8ba57674fd3bc2b8bf7acf1fa5c1e373fd9a0adb 100644
--- a/reco/tasks/CbmTaskDigiEventQa.cxx
+++ b/reco/tasks/CbmTaskDigiEventQa.cxx
@@ -38,7 +38,7 @@ CbmTaskDigiEventQa::~CbmTaskDigiEventQa() {}
 
 
 // -----   Configuration   ---------------------------------------------------
-void CbmTaskDigiEventQa::Config(const CbmRecoConfig& config)
+void CbmTaskDigiEventQa::Config(const cbm::algo::MainConfig& config)
 {
 
   // The histogram ranges are defined by the event building windows. The number of bins
diff --git a/reco/tasks/CbmTaskDigiEventQa.h b/reco/tasks/CbmTaskDigiEventQa.h
index 1710fb6b85832fb548d57bf1f76bbd0ab666aae1..c1779db923e8232ec088aa4f8873ae4afbadf68c 100644
--- a/reco/tasks/CbmTaskDigiEventQa.h
+++ b/reco/tasks/CbmTaskDigiEventQa.h
@@ -12,11 +12,11 @@
 
 #include <vector>
 
+#include "MainConfig.h"
 #include "algo/qa/DigiEventQa.h"
 #include "algo/qa/Histo1D.h"
 
 
-class CbmRecoConfig;
 class TH1D;
 
 /** @class CbmTaskDigiEventQa
@@ -48,7 +48,7 @@ public:
    **
    ** Histograms are created with limits adjusted to the windows use by the event builder.
    **/
-  void Config(const CbmRecoConfig& config);
+  void Config(const cbm::algo::MainConfig& config);
 
 
   /** @brief Task execution **/