diff --git a/sim/response/CMakeLists.txt b/sim/response/CMakeLists.txt
index 3594a5d75bf08c1e9e7de69f9fd4e3135f52582e..0b9ea5aff007cce5644210428a5fc2b2cc6384ec 100644
--- a/sim/response/CMakeLists.txt
+++ b/sim/response/CMakeLists.txt
@@ -1,3 +1,7 @@
+#subdirectories
+add_subdirectory(app)
+add_subdirectory(steer)
+
 set(INCLUDE_DIRECTORIES
   ${CMAKE_CURRENT_SOURCE_DIR}/base
   )
diff --git a/sim/response/app/Application.cxx b/sim/response/app/Application.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..32cebeb9ee9830e28c61f9054bb1aa082f877f50
--- /dev/null
+++ b/sim/response/app/Application.cxx
@@ -0,0 +1,45 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Frederic Linz [committer], Volker Friese */
+
+/** @file Application.cxx
+ ** @author Frederic Linz <f.linz@gsi.de>
+ ** @date 09.01.2024
+ **/
+
+#include "Application.h"
+
+#include "Config.h"
+
+using std::string;
+
+namespace cbm::sim::digitization
+{
+
+  // -----   Constructor   ----------------------------------------------------
+  Application::Application(ProgramOptions const& opt) : fOpt(opt) {}
+  // --------------------------------------------------------------------------
+
+
+  // -----   Run the reconstruction   -----------------------------------------
+  void Application::Exec()
+  {
+
+    // --- Use program options
+    fRun.SetOutput(fOpt.OutputFile().c_str());
+    fRun.SetTraFiles(fOpt.TraFiles());
+    fRun.SetParFile(fOpt.ParFile().c_str());
+    fRun.SetGeoSetupTag(fOpt.SetupTag().c_str());
+    if (fOpt.Overwrite()) fRun.AllowOverwrite();
+
+    // --- Read configuration from YAML file
+    cbm::sim::digitization::Config config;
+    config.LoadYaml(fOpt.ConfigFile());
+    fRun.SetConfig(config);
+
+    // --- Execute reconstruction run
+    fRun.Exec();
+  }
+  // --------------------------------------------------------------------------
+
+}  // namespace cbm::sim::digitization
diff --git a/sim/response/app/Application.h b/sim/response/app/Application.h
new file mode 100644
index 0000000000000000000000000000000000000000..b9c47d48c4291ac56be3a83ac22eeda10cbd4832
--- /dev/null
+++ b/sim/response/app/Application.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Frederic Linz [committer], Volker Friese */
+
+/** @file Application.h
+ ** @author Frederic Linz <f.linz@gsi.de>
+ ** @date 09.01.2024
+ **/
+
+
+#ifndef CBMSIM_DIGITIZATION_APP_APPLICATION_H
+#define CBMSIM_DIGITIZATION_APP_APPLICATION 1
+
+#include "ProgramOptions.h"
+#include "Run.h"
+
+namespace cbm::sim::digitization
+{
+
+  class Application {
+
+
+   public:
+    /** @brief Standard constructor, initialises the application
+     ** @param opt  **/
+    explicit Application(ProgramOptions const& opt);
+
+    /** @brief Copy constructor forbidden **/
+    Application(const Application&) = delete;
+
+    /** @brief Assignment operator forbidden **/
+    void operator=(const Application&) = delete;
+
+    /** @brief Destructor **/
+    ~Application() = default;
+
+    /** @brief Run the application **/
+    void Exec();
+
+   private:
+    const std::string& OutputFile() const;
+    const std::vector<std::string>& TraFile() const;
+    const std::string& ParFile() const;
+    const std::string& SetupTag() const;
+    const std::string& ConfigFile() const;
+
+
+   private:
+    ProgramOptions const& fOpt;  ///< Program options object
+    Run fRun = {};               ///< Reconstruction run
+  };
+
+}  // namespace cbm::sim::digitization
+
+#endif /* CBMSIM_DIGITIZATION_APP_APPLICATION */
diff --git a/sim/response/app/CMakeLists.txt b/sim/response/app/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ce446741577b41f0fafb30b93b62bf235bcaadad
--- /dev/null
+++ b/sim/response/app/CMakeLists.txt
@@ -0,0 +1,26 @@
+# CMakeList file for binary cbmatc
+# F.Linz,	09. January 2024
+
+set(SRCS
+  Application.cxx
+  ProgramOptions.cxx
+  main.cxx
+  )
+
+set(HEADERS
+  Application.h
+  ProgramOptions.h
+  )
+
+
+add_executable(cbmsim_digitization ${SRCS} ${HEADERS})
+
+target_link_libraries(cbmsim_digitization
+  PUBLIC
+    CbmSimDigitizationSteer
+    CbmSimResponse
+  PRIVATE
+    Boost::program_options
+  )
+
+install(TARGETS cbmsim_digitization DESTINATION bin)
diff --git a/sim/response/app/ProgramOptions.cxx b/sim/response/app/ProgramOptions.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7ca5ee441c3a33ae09053f539a2f868b8dc6570f
--- /dev/null
+++ b/sim/response/app/ProgramOptions.cxx
@@ -0,0 +1,84 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Frederic Linz [committer], Volker Friese */
+
+/** @file ProgramOptions.cxx
+ ** @author Frederic Linz <f.linz@gsi.de>
+ ** @date 09.01.2024
+ **
+ ** Code taken from reco/app/cbmreco_fairrun/ProgramOptions.cxx (J. de Cuveland)
+ **/
+
+#include "ProgramOptions.h"
+
+#include <Logger.h>
+
+#include <boost/program_options.hpp>
+
+#include <iostream>
+
+namespace po = boost::program_options;
+
+using std::string;
+using std::vector;
+
+namespace cbm::sim::digitization
+{
+
+  // -----   Parse command line   ---------------------------------------------
+  void ProgramOptions::ParseOptions(int argc, char* argv[])
+  {
+
+    // --- Define generic options
+    po::options_description generic("Generic options");
+    auto generic_add = generic.add_options();
+    generic_add("help,h", "display this help and exit");
+
+    // --- Define configuration options
+    string defconfig = std::getenv("VMCWORKDIR");
+    defconfig.append("/");
+    defconfig.append(DEFAULT_CONFIG);
+    po::options_description config("Configuration");
+    auto config_add = config.add_options();
+    config_add("output,o", po::value<string>(&fOutput)->value_name("<file name>"),
+               "name of the output ROOT file with digi data");
+    config_add("transport,t", po::value<vector<string>>(&fTra)->value_name("<file names>")->multitoken(),
+               "names of a transport input sources (ROOT files)");
+    config_add("parameter,p", po::value<string>(&fPar)->value_name("<file name>"),
+               "name of a parameter ROOT file (FairRuntimeDb format)");
+    config_add("config,c", po::value<string>(&fConfig)->value_name("<file name>")->default_value(defconfig),
+               "name of a YAML file describing the configuration of reconstruction");
+    config_add("setup,s", po::value<string>(&fSetup)->value_name("<tag>")->default_value(DEFAULT_SETUP),
+               "geometry setup tag");
+    config_add("overwrite,w", po::bool_switch(&fOverwrite)->default_value(false),
+               "allow to overwite an existing output file");
+
+    // --- Allowed options
+    po::options_description cmdline_options("Allowed options");
+    cmdline_options.add(generic).add(config);
+
+    // --- Parse command line
+    po::variables_map vars;
+    po::store(po::parse_command_line(argc, argv, cmdline_options), vars);
+    po::notify(vars);
+
+    // --- Help: print help information and exit program
+    if (vars.count("help") != 0u) {
+      std::cout << cmdline_options << std::endl;
+      exit(EXIT_SUCCESS);
+    }
+
+    // --- Catch mandatory parameters not being specified
+    if (vars.count("output") == 0u) {
+      throw std::runtime_error("no output file name specified");
+    }
+    if (vars.count("transport") == 0u) {
+      throw std::runtime_error("no transport file name specified");
+    }
+    if (vars.count("parameter") == 0u) {
+      throw std::runtime_error("no parameter file name specified");
+    }
+  }
+  // --------------------------------------------------------------------------
+
+}  // namespace cbm::sim::digitization
diff --git a/sim/response/app/ProgramOptions.h b/sim/response/app/ProgramOptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..8d3058afb8596cc493d9d457d19bf14edf05b547
--- /dev/null
+++ b/sim/response/app/ProgramOptions.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Frederic Linz [committer], Volker Friese, Jan de Cuveland */
+
+/** @file ProgramOptions.h
+ ** @author Frederic Linz <f.linz@gsi.de>
+ ** @date 09.01.2024
+ **
+ ** Code taken from reco/app/cbmreco_fairrun/ProgramOptions.h (J. de Cuveland)
+ **/
+
+#ifndef CBMSIM_DIGITIZATION_APP_PROGRAMOPTIONS_H
+#define CBMSIM_DIGITIZATION_APP_PROGRAMOPTIONS_H 1
+
+#define DEFAULT_CONFIG "sim/response/config/DigiConfig_event_ideal.yaml"
+#define DEFAULT_SETUP "sis100_electron"
+
+
+#include <string>
+#include <vector>
+
+namespace cbm::sim::digitization
+{
+
+  /** @class ProgramOptions
+   ** @author Frederic Linz <f.linz@gsi.de>
+   ** @since 09 January 2024
+   **
+   ** Program option class for the application cbmatc
+   **/
+  class ProgramOptions {
+   public:
+    /** @brief Standard constructor with command line arguments **/
+    ProgramOptions(int argc, char* argv[]) { ParseOptions(argc, argv); }
+
+    /** @brief Copy constructor forbidden **/
+    ProgramOptions(const ProgramOptions&) = delete;
+
+    /** @brief Assignment operator forbidden **/
+    ProgramOptions& operator=(const ProgramOptions&) = delete;
+
+    /** @brief Destructor **/
+    ~ProgramOptions() = default;
+
+    /** @brief Get output file name (.root format) **/
+    [[nodiscard]] const std::string& OutputFile() const { return fOutput; }
+
+    /** @brief Get transport file name **/
+    [[nodiscard]] const std::vector<std::string>& TraFiles() const { return fTra; }
+
+    /** @brief Get parameter file name **/
+    [[nodiscard]] const std::string& ParFile() const { return fPar; }
+
+    /** @brief Get configuration file name (YAML format) **/
+    [[nodiscard]] const std::string& ConfigFile() const { return fConfig; }
+
+    /** @brief Get geometry setup tag **/
+    [[nodiscard]] const std::string& SetupTag() const { return fSetup; }
+
+    /** @brief Get overwrite option **/
+    [[nodiscard]] bool Overwrite() const { return fOverwrite; }
+
+
+   private:
+    /** @brief Parse command line arguments using boost program_options **/
+    void ParseOptions(int argc, char* argv[]);
+
+
+   private:                         // members
+    std::string fOutput = "";       ///< Output file name (ROOT format)
+    std::vector<std::string> fTra;  ///< List of transport input sources (ROOT format)
+    std::string fPar    = "";       ///< Parameter file name (ROOT format)
+    std::string fConfig = "";       ///< Configuration file name (YAML format)
+    std::string fSetup  = "";       ///< Geometry setup tag
+    bool fOverwrite     = false;    ///< Enable overwriting of existing output file
+  };
+
+}  // namespace cbm::sim::digitization
+
+#endif /* CBMSIM_DIGITIZATION_APP_PROGRAMOPTIONS_H */
diff --git a/sim/response/app/main.cxx b/sim/response/app/main.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ebec1cfc99593ca2c81c6a369fa485901179f298
--- /dev/null
+++ b/sim/response/app/main.cxx
@@ -0,0 +1,26 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Frederic Linz [committer], Volker Friese, Jan de Cuveland */
+#include "Application.h"
+#include "ProgramOptions.h"
+
+#include <Logger.h>
+
+using namespace cbm::sim::digitization;
+
+int main(int argc, char* argv[])
+{
+  LOG(info) << "*****   CBM Digitization   *****";
+  try {
+    ProgramOptions opt(argc, argv);
+    Application app(opt);
+    app.Exec();
+  }
+  catch (std::exception const& e) {
+    LOG(error) << e.what() << "; terminating.";
+    return EXIT_FAILURE;
+  }
+
+  LOG(info) << "CBM Digitization: Program completed successfully; exiting.";
+  return EXIT_SUCCESS;
+}
diff --git a/sim/response/base/Defs.h b/sim/response/base/Defs.h
index 0030057a5ba4c3b307b8d657f34d322f33afbcb8..21a8a7e9b36e3c977923d25091bd3f7ce4b645b7 100644
--- a/sim/response/base/Defs.h
+++ b/sim/response/base/Defs.h
@@ -20,14 +20,16 @@ namespace cbm::sim
   enum class Mode
   {
     Timebased,
-    EventByEvent
+    EventByEvent,
+    Undefined
   };
 
   /** @enum Time distribution model **/
   enum class TimeDist
   {
     Poisson,
-    Uniform
+    Uniform,
+    Undefined
   };
 
 
diff --git a/sim/response/config/DigiConfig_event.yaml b/sim/response/config/DigiConfig_event.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6829a650e5296e05edf87e4641bd4e4b7e52a76e
--- /dev/null
+++ b/sim/response/config/DigiConfig_event.yaml
@@ -0,0 +1,20 @@
+global:
+  log_level: INFO
+  log_verbose: LOW
+  log_color: true
+  mode: event
+  nTimeslices: -1
+  firstTimeslice: -1
+detectors:
+  deactivate: ""
+  deactivateAllBut: ""
+timeslice:
+  timeslicelength: 1.e5     
+  storeAllTimeslices: false
+  startTime: 1000
+  timeDist: poisson
+background:
+  produceNoise: false
+sources:
+  - { id: 0, rate: 1.e5, treeAccessMode: regular, embedToId: -1 }
+#TODO: could be potential error to add input via -t file.tra.root in different order than list of sources here
diff --git a/sim/response/config/DigiConfig_timeslice.yaml b/sim/response/config/DigiConfig_timeslice.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7989ccf5a0157cd38768677855b9cd1b9b572322
--- /dev/null
+++ b/sim/response/config/DigiConfig_timeslice.yaml
@@ -0,0 +1,21 @@
+global:
+  log_level: INFO
+  log_verbose: LOW
+  log_color: true
+  mode: timeslice
+  nTimeslices: -1
+  firstTimeslice: -1
+detectors:
+  deactivate: ""
+  deactivateAllBut: ""
+timeslice:
+  timeslicelength: 1.e13
+  storeAllTimeslices: false
+  startTime: 1000
+  timeDist: poisson
+background:
+  produceNoise: false
+sources:
+  - { id: 0, rate: 1.e5, treeAccessMode: regular, embedToId: -1 }
+    #  - { id: 1, rate: 1.e7, treeAccessMode: regular, embedToId: -1 }
+#TODO: could be potential error to add input via -t file.tra.root in different order than list of sources here
diff --git a/sim/response/steer/CMakeLists.txt b/sim/response/steer/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..314b990001aabc1664c4c6d21f5b6b22a198f0df
--- /dev/null
+++ b/sim/response/steer/CMakeLists.txt
@@ -0,0 +1,31 @@
+# CMakeList file for library libCbmSimDigitizationSteer
+# F. Linz,     09 January 2024
+
+set(SRCS
+  Config.cxx
+  Run.cxx
+  )
+
+set(INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(LIBRARY_NAME CbmSimDigitizationSteer)
+set(LINKDEF RootLinkDef.h)
+set(PUBLIC_DEPENDENCIES
+  CbmData
+  FairRoot::Base
+  ROOT::Core
+  external::yaml-cpp
+  )
+
+set(PRIVATE_DEPENDENCIES
+  CbmBase
+  FairLogger::FairLogger
+  FairRoot::Online
+  ROOT::Hist
+  ROOT::RHTTP
+  CbmSimSteer
+  CbmSimResponse
+  Algo
+  )
+
+generate_cbm_library()
diff --git a/sim/response/steer/Config.cxx b/sim/response/steer/Config.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6cd0076dceb48169515e970fb2295a5ac3fd1913
--- /dev/null
+++ b/sim/response/steer/Config.cxx
@@ -0,0 +1,244 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Frederic Linz [committer], Volker Friese */
+
+/** @file .cxx
+ ** @author Frederic Linz <f.linz@gsi.de>
+ ** @date 10.01.2024
+ **/
+
+
+#include "Config.h"
+
+#include <Logger.h>
+
+#include <fstream>
+
+#include <yaml-cpp/yaml.h>
+
+using std::string;
+
+namespace cbm::sim::digitization
+{
+
+
+  // -----   Load settings from YAML file   -------------------------------------
+  void Config::LoadYaml(const string& fileName)
+  {
+
+    LOG(info) << "Config: Reading configuration from " << fileName;
+    YAML::Node settings = YAML::LoadFile(fileName);
+
+    // --- Global settings
+    f_glb_logLevel   = settings["global"]["log_level"].as<string>();
+    f_glb_logVerbose = settings["global"]["log_verbose"].as<string>();
+    f_glb_logColor   = settings["global"]["log_color"].as<string>();
+    f_glb_mode       = ToCbmDigiMode(settings["global"]["mode"].as<string>());
+    f_glb_numTs      = settings["global"]["nTimeslices"].as<int>();
+    f_glb_firstTs    = settings["global"]["firstTimeslice"].as<int>();
+
+    // --- Detector choice
+    f_det_deactivateAllBut = ToECbmModuleId(settings["detectors"]["deactivateAllBut"].as<string>());
+    f_det_deactivate       = ToECbmModuleId(settings["detectors"]["deactivate"].as<string>());
+
+    // --- Timeslice settings
+    f_ts_tslength   = settings["timeslice"]["timeslicelength"].as<float>();
+    f_ts_storeAllTS = settings["timeslice"]["storeAllTimeslices"].as<bool>();
+    f_ts_startTime  = settings["timeslice"]["startTime"].as<float>();
+    f_ts_timeDist   = ToCbmSimTimeDist(settings["timeslice"]["timeDist"].as<string>());
+
+    // --- Background settings
+    f_bg_produceNoise = settings["background"]["produceNoise"].as<bool>();
+
+    // --- Input sources
+    YAML::Node sources = settings["sources"];
+
+    for (auto source : sources) {
+      f_src_id.push_back(source["id"].as<int>());
+      f_src_rate.push_back(source["rate"].as<float>());
+      f_src_treeAccessMode.push_back(ToECbmTreeAccess(source["treeAccessMode"].as<string>()));
+      f_src_embedToId.push_back(source["embedToId"].as<int>());
+    }
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // ------   String to ECbmRecoMode   ------------------------------------------
+  cbm::sim::Mode Config::ToCbmDigiMode(string choice)
+  {
+    string temp = choice;
+    std::transform(temp.begin(), temp.end(), temp.begin(), [](unsigned char c) { return std::tolower(c); });
+    if (temp == "timeslice")
+      return cbm::sim::Mode::Timebased;
+    else if (temp == "event")
+      return cbm::sim::Mode::EventByEvent;
+    else
+      return cbm::sim::Mode::Undefined;
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // -----   ECbmRecoMode to string   -------------------------------------------
+  string Config::ToString(cbm::sim::Mode mode)
+  {
+    if (mode == cbm::sim::Mode::Timebased)
+      return "timeslice";
+    else if (mode == cbm::sim::Mode::EventByEvent)
+      return "event";
+    else
+      return "undefined";
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // -----   String to cbm::sim::TimeDist   -------------------------------------
+  cbm::sim::TimeDist Config::ToCbmSimTimeDist(string choice)
+  {
+    string temp = choice;
+    std::transform(temp.begin(), temp.end(), temp.begin(), [](unsigned char c) { return std::tolower(c); });
+    if (temp == "poisson")
+      return cbm::sim::TimeDist::Poisson;
+    else if (temp == "uniform")
+      return cbm::sim::TimeDist::Uniform;
+    else
+      return cbm::sim::TimeDist::Undefined;
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // -----   cbm::sim::TimeDist to string   -------------------------------------
+  string Config::ToString(cbm::sim::TimeDist dist)
+  {
+    if (dist == cbm::sim::TimeDist::Poisson)
+      return "poisson";
+    else if (dist == cbm::sim::TimeDist::Uniform)
+      return "uniform";
+    else
+      return "undefined";
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // -----  Convert std::string to ECbmModuleId  --------------------------------
+  ECbmModuleId Config::ToECbmModuleId(std::string moduleString)
+  {
+    std::string temp = moduleString;
+    std::transform(temp.begin(), temp.end(), temp.begin(), [](unsigned char c) { return std::tolower(c); });
+    if (temp == "mvd")
+      return ECbmModuleId::kMvd;
+    else if (temp == "sts")
+      return ECbmModuleId::kSts;
+    else if (temp == "rich")
+      return ECbmModuleId::kRich;
+    else if (temp == "much")
+      return ECbmModuleId::kMuch;
+    else if (temp == "trd")
+      return ECbmModuleId::kTrd;
+    else if (temp == "tof")
+      return ECbmModuleId::kTof;
+    else if (temp == "psd")
+      return ECbmModuleId::kPsd;
+    else if (temp == "fsd")
+      return ECbmModuleId::kFsd;
+    else if (temp == "bmon")
+      return ECbmModuleId::kBmon;
+    else
+      return ECbmModuleId::kNotExist;
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // ----- Convert ECbmModuleId to std::string  ---------------------------------
+  string Config::ToString(ECbmModuleId moduleId)
+  {
+    if (moduleId == ECbmModuleId::kMvd)
+      return "mvd";
+    else if (moduleId == ECbmModuleId::kSts)
+      return "sts";
+    else if (moduleId == ECbmModuleId::kRich)
+      return "rich";
+    else if (moduleId == ECbmModuleId::kMuch)
+      return "much";
+    else if (moduleId == ECbmModuleId::kTrd)
+      return "trd";
+    else if (moduleId == ECbmModuleId::kTof)
+      return "tof";
+    else if (moduleId == ECbmModuleId::kPsd)
+      return "psd";
+    else if (moduleId == ECbmModuleId::kFsd)
+      return "fsd";
+    else if (moduleId == ECbmModuleId::kBmon)
+      return "bmon";
+    else
+      return "";
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // -----  Convert std::string to ECbmTreeAccess  ------------------------------
+  ECbmTreeAccess Config::ToECbmTreeAccess(std::string treeAccessString)
+  {
+    std::string temp = treeAccessString;
+    std::transform(temp.begin(), temp.end(), temp.begin(), [](unsigned char c) { return std::tolower(c); });
+    if (temp == "random")
+      return ECbmTreeAccess::kRandom;
+    else if (temp == "repeat")
+      return ECbmTreeAccess::kRepeat;
+    else
+      return ECbmTreeAccess::kRegular;
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // -----  Convert ECbmTreeAccess to std::string  ------------------------------
+  string Config::ToString(ECbmTreeAccess treeAccessString)
+  {
+    if (treeAccessString == ECbmTreeAccess::kRandom)
+      return "random";
+    else if (treeAccessString == ECbmTreeAccess::kRepeat)
+      return "repeat";
+    else
+      return "regular";
+  }
+  // ----------------------------------------------------------------------------
+
+
+  // -----   Save settings to YAML node   ---------------------------------------
+  YAML::Node Config::ToYaml()
+  {
+    YAML::Node settings;
+
+    // --- Global settings
+    settings["global"]["log_level"]      = f_glb_logLevel;
+    settings["global"]["log_verbose"]    = f_glb_logVerbose;
+    settings["global"]["log_color"]      = f_glb_logColor;
+    settings["global"]["mode"]           = ToString(f_glb_mode);
+    settings["global"]["nTimeslices"]    = f_glb_numTs;
+    settings["global"]["firstTimeslice"] = f_glb_firstTs;
+
+    // --- Detector choice
+    settings["detectors"]["deactivateAllBut"] = ToString(f_det_deactivateAllBut);
+    settings["detectors"]["deactivate"]       = ToString(f_det_deactivate);
+
+    // --- Timeslice settings
+    settings["timeslice"]["timeslicelength"]    = f_ts_tslength;
+    settings["timeslice"]["storeAllTimeslices"] = f_ts_storeAllTS;
+    settings["timeslice"]["startTime"]          = f_ts_startTime;
+    settings["timeslice"]["timeDist"]           = ToString(f_ts_timeDist);
+
+    // --- Background settings
+    settings["background"]["produceNoise"] = f_bg_produceNoise;
+
+    // --- Input sources
+    for (int i = 0; i < (int) f_src_id.size(); ++i) {
+      settings["sources"][i]["id"]             = f_src_id.at(i);
+      settings["sources"][i]["rate"]           = f_src_rate.at(i);
+      settings["sources"][i]["treeAccessMode"] = ToString(f_src_treeAccessMode.at(i));
+      settings["sources"][i]["embedToId"]      = f_src_embedToId.at(i);
+    }
+
+    return settings;
+  }
+  // ----------------------------------------------------------------------------
+
+}  // namespace cbm::sim::digitization
diff --git a/sim/response/steer/Config.h b/sim/response/steer/Config.h
new file mode 100644
index 0000000000000000000000000000000000000000..8d8c167b9fd10fb03fcd6306a2da7a60cefa05d9
--- /dev/null
+++ b/sim/response/steer/Config.h
@@ -0,0 +1,120 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Frederic Linz [committer], Volker Friese */
+
+/** @file Config.h
+ ** @author Frederic Linz <f.linz@gsi.de>
+ ** @date 09.01.2024
+ **/
+
+#ifndef CBMSIM_DIGITIZATION_STEER_CONFIG_H
+#define CBMSIM_DIGITIZATION_STEER_CONFIG_H 1
+
+#include "CbmDefs.h"
+#include "CbmDigitization.h"
+
+#include <array>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <yaml-cpp/yaml.h>
+
+namespace cbm::sim::digitization
+{
+
+  /** @class Config
+   ** @author Frederic Linz <f.linz@gsi.de>
+   ** @date 09.01.2024
+   **
+   ** Configuration for the analysis tree converter, replacing run_digi_json_config.C.
+   ** With interfaces to YAML.
+   **/
+  class Config {
+   public:
+    /** @brief Constructor **/
+    Config() = default;
+
+
+    /** @brief Destructor **/
+    virtual ~Config() = default;
+
+
+    /** @brief Load from YAML file
+     ** @param filename  Name of input YAML file
+     **/
+    void LoadYaml(const std::string& filename);
+
+
+    /** @brief String output (YAML format) **/
+    std::string ToString()
+    {
+      std::stringstream out;
+      out << ToYaml();
+      return out.str();
+    }
+
+
+    /** @brief Save to YAML file
+     ** @param filename  Name of output YAML file
+     **/
+    void SaveYaml(const std::string& filename)
+    {
+      std::ofstream fout(filename);
+      fout << ToYaml();
+    }
+
+
+   private:
+    cbm::sim::Mode ToCbmDigiMode(std::string tag);
+    std::string ToString(cbm::sim::Mode mode);
+
+    cbm::sim::TimeDist ToCbmSimTimeDist(std::string tag);
+    std::string ToString(cbm::sim::TimeDist dist);
+
+    ECbmModuleId ToECbmModuleId(std::string moduleString);
+    std::string ToString(ECbmModuleId moduleId);
+
+    ECbmTreeAccess ToECbmTreeAccess(std::string treeAccessString);
+    std::string ToString(ECbmTreeAccess treeAccessString);
+
+    /** @brief Save to YAML node **/
+    YAML::Node ToYaml();
+
+
+   public:
+    // --- Global settings
+    std::string f_glb_logLevel   = "INFO";
+    std::string f_glb_logVerbose = "LOW";
+    std::string f_glb_logColor   = "true";
+    cbm::sim::Mode f_glb_mode    = cbm::sim::Mode::Undefined;
+    int f_glb_numTs              = -1;
+    int f_glb_firstTs            = 0;
+
+    // --- Detector selection
+    ECbmModuleId f_det_deactivateAllBut = ECbmModuleId::kNotExist;
+    ECbmModuleId f_det_deactivate =
+      ECbmModuleId::kNotExist;  // TODO: option should be able to deal with several detectors
+
+    // --- Timeslice settings
+    float f_ts_tslength  = 1.e5;
+    float f_ts_startTime = 1000.;
+    bool f_ts_storeAllTS = false;
+    cbm::sim::TimeDist f_ts_timeDist =
+      cbm::sim::TimeDist::Undefined;  // Event time distribution model: poisson or uniform
+
+    // --- Background settings
+    bool f_bg_produceNoise = false;
+
+    // --- Input sources settings
+    std::vector<int> f_src_id;
+    std::vector<float> f_src_rate;
+    std::vector<ECbmTreeAccess> f_src_treeAccessMode;
+    std::vector<int> f_src_embedToId;
+  };
+
+}  // namespace cbm::sim::digitization
+
+
+#endif /* CBMSIM_DIGITIZATION_STEER_CONFIG_H */
diff --git a/sim/response/steer/RootLinkDef.h b/sim/response/steer/RootLinkDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba504d41a7aca47eb5d1c4aac8c27c729c5d1461
--- /dev/null
+++ b/sim/response/steer/RootLinkDef.h
@@ -0,0 +1,17 @@
+/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Frederic Linz [committer], Volker Friese */
+
+// ===== LinkDef for digitizazion/task =====
+
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+// --- Classes
+#pragma link C++ class cbm::sim::digitization::Run + ;
+
+
+#endif /* __CINT__ */
diff --git a/sim/response/steer/Run.cxx b/sim/response/steer/Run.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..bdab3b756d9daeb6b4ed6ed8a06033062c2c07cf
--- /dev/null
+++ b/sim/response/steer/Run.cxx
@@ -0,0 +1,176 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Frederic Linz [committer], Volker Friese, Florian Uhlig */
+
+/** @file Run.cxx
+ ** @author Frederic Linz <f.linz@gsi.de>
+ ** @date 27.10.2023
+ **/
+
+#include "Run.h"
+
+#include "CbmDigitization.h"
+#include "CbmSetup.h"
+
+#include <FairEventHeader.h>
+#include <FairMonitor.h>
+#include <Logger.h>
+
+#include <TFile.h>
+#include <TGeoManager.h>
+#include <TStopwatch.h>
+#include <TString.h>
+#include <TTree.h>
+
+#include <cassert>
+#include <iostream>
+
+#include <sys/stat.h>
+
+namespace cbm::sim::digitization
+{
+
+
+  // -----   Constructor   ----------------------------------------------------
+  Run::Run() : TNamed("Run", "CBM AnalysisTree Converter Run") {}
+  // --------------------------------------------------------------------------
+
+
+  // -----   Destructor   -----------------------------------------------------
+  Run::~Run() { LOG(debug) << "Destructing " << fName; }
+  // --------------------------------------------------------------------------
+
+
+  // -----   Check existence of a file   --------------------------------------
+  bool Run::CheckFile(const char* fileName)
+  {
+    struct stat buffer;
+    return (stat(fileName, &buffer) == 0);
+  }
+  // --------------------------------------------------------------------------
+
+
+  // -----   Execute reconstruction run   -------------------------------------
+  void Run::Exec()
+  {
+    // --- Mirror options and configuration
+    LOG(info) << GetName() << ": Output file is         " << fOutput;
+    if (CheckFile(fOutput.Data()) && !fOverwrite) throw std::runtime_error("Output file already exists");
+    for (auto trafile : fTra) {
+      LOG(info) << GetName() << ": Transport input source is      " << trafile;
+      if (!CheckFile(trafile.Data())) throw std::runtime_error("Transport file does not exist");
+    }
+    LOG(info) << GetName() << ": Parameter file is      " << fPar;
+    if (!CheckFile(fPar.Data())) throw std::runtime_error("Parameter file does not exist");
+    LOG(info) << GetName() << ": Geometry setup is      " << fSetupTag;
+    LOG(info) << "Configuration: \n" << fConfig.ToString() << "\n";
+
+    // --- Timer
+    TStopwatch timer;
+    timer.Start();
+
+    // --- Logger settings
+    FairLogger::GetLogger()->SetLogScreenLevel(fConfig.f_glb_logLevel.data());
+    FairLogger::GetLogger()->SetLogVerbosityLevel(fConfig.f_glb_logVerbose.data());
+    FairLogger::GetLogger()->SetColoredLog(fConfig.f_glb_logColor.data());
+
+    // --- Input sources
+    int sourceId = 0;
+    for (auto trafile : fTra) {
+      if (fConfig.f_src_embedToId.at(sourceId) > 0) {
+        LOG(info) << GetName() << ": Embeding input " << trafile << " (Rate will be ignored)";
+        fRun.EmbedInput(fConfig.f_src_id.at(sourceId), trafile, fConfig.f_src_embedToId.at(sourceId));
+      }
+      else {
+        if (fConfig.f_glb_mode == cbm::sim::Mode::EventByEvent && fConfig.f_src_id.size() > 1)
+          throw std::runtime_error("Event mixing is not possible in event-by-event mode!");
+
+        LOG(info) << GetName() << ": Adding input " << trafile;
+        fRun.AddInput(fConfig.f_src_id.at(sourceId), trafile, fConfig.f_ts_timeDist, fConfig.f_src_rate.at(sourceId),
+                      fConfig.f_src_treeAccessMode.at(sourceId));
+      }
+    }
+    fRun.SetParameterRootFile(fPar);
+    fRun.SetMonitorFile((GetFileName(fOutput) + ".moni_digi.root").c_str());
+    fRun.SetOutputFile(fOutput, fOverwrite);
+
+    // --- Set digitization parameters
+    fRun.SetMode(fConfig.f_glb_mode);
+    if (fConfig.f_glb_mode == cbm::sim::Mode::Timebased) {
+      fRun.SetTimeSliceLength(fConfig.f_ts_tslength);
+      fRun.SetStartTime(fConfig.f_ts_startTime);
+      fRun.StoreAllTimeSlices(fConfig.f_ts_storeAllTS);
+    }
+    fRun.SetProduceNoise(fConfig.f_bg_produceNoise);
+
+    // --- Geometry setup
+    LOG(info) << GetName() << ": Loading setup " << fSetupTag;
+    fSetup = CbmSetup::Instance();
+    fSetup->LoadSetup(fSetupTag);
+
+    if (fConfig.f_det_deactivateAllBut != ECbmModuleId::kNotExist)
+      fRun.DeactivateAllBut(fConfig.f_det_deactivateAllBut);
+    if (fConfig.f_det_deactivate != ECbmModuleId::kNotExist) fRun.Deactivate(fConfig.f_det_deactivate);
+
+    timer.Stop();
+    double timeInit = timer.RealTime();
+    timer.Start();
+
+    // --- Execute run
+    std::cout << std::endl << std::endl;
+    LOG(info) << GetName() << ": Starting run" << std::endl;
+    fRun.Run(fConfig.f_glb_firstTs, fConfig.f_glb_numTs);
+
+    // --- Finish
+    timer.Stop();
+    double timeExec = timer.RealTime();
+    FairMonitor::GetMonitor()->Print();
+    std::cout << std::endl << std::endl;
+    LOG(info) << GetName() << ": Execution successful";
+    for (auto trafile : fTra)
+      LOG(info) << GetName() << ": Transport file was      " << trafile;
+    LOG(info) << GetName() << ": Parameter file was      " << fPar;
+    LOG(info) << GetName() << ": Output file is          " << fOutput;
+    LOG(info) << GetName() << ": Execution time: Init    " << timeInit << " s, Exec " << timeExec << "s";
+  }
+  // --------------------------------------------------------------------------
+
+
+  // -----  Get file name without extension   ---------------------------------
+  std::string Run::GetFileName(const TString file)
+  {
+    std::string temp(file.Data());
+    size_t index = temp.find_last_of(".");
+    temp         = temp.substr(0, index);
+    std::transform(temp.begin(), temp.end(), temp.begin(), [](unsigned char c) { return c; });
+    return temp;
+  }
+  // --------------------------------------------------------------------------
+
+
+  // -----  Read configuration from YAML file   -------------------------------
+  void Run::LoadConfig(const char* fileName)
+  {
+    TString file(fileName);
+    if (file.IsNull()) {
+      file = std::getenv("VMCWORKDIR");
+      file += "/sim/response/config/DigiConfig_event.yaml";
+    }
+    LOG(info) << GetName() << ": Loading configuration from " << file;
+    fConfig.LoadYaml(file.Data());
+  }
+  // --------------------------------------------------------------------------
+
+
+  // ----  Set input sources  -------------------------------------------------
+  void Run::SetTraFiles(const std::vector<std::string> files)
+  {
+    for (auto file : files) {
+      fTra.push_back(file.c_str());
+    }
+  }
+  // --------------------------------------------------------------------------
+
+}  // namespace cbm::sim::digitization
+
+ClassImp(cbm::sim::digitization::Run)
diff --git a/sim/response/steer/Run.h b/sim/response/steer/Run.h
new file mode 100644
index 0000000000000000000000000000000000000000..08ff0a60ec1e3203c7fc664845bfa5b820494c72
--- /dev/null
+++ b/sim/response/steer/Run.h
@@ -0,0 +1,130 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Frederic Linz [committer], Volker Friese */
+
+/** @file Run.h
+ ** @author Frederic Linz <f.linz@gsi.de>
+ ** @date 09.01.2024
+ **/
+
+#ifndef CBMSIM_DIGITIZATION_STEER_RUN_H
+#define CBMSIM_DIGITIZATION_STEER_RUN_H 1
+
+#include "Config.h"
+
+#include <TNamed.h>
+#include <TString.h>
+
+#include <string>
+#include <vector>
+
+class CbmSetup;
+class FairTask;
+class CbmDigitization;
+class TTree;
+
+namespace cbm::sim::digitization
+{
+
+  class Run : public TNamed {
+
+   public:
+    /** @brief Constructor **/
+    Run();
+
+
+    /** @brief Destructor  **/
+    virtual ~Run();
+
+
+    /** @brief Allow overwriting if output file already exists **/
+    void AllowOverwrite() { fOverwrite = true; }
+
+
+    /** @brief Run digitization **/
+    void Exec();
+
+
+    /** @brief Settings object **/
+    const Config& GetConfig() const { return fConfig; }
+
+
+    /** @brief Get file name without ending
+     ** @param file  full file name including ending **/
+    std::string GetFileName(const TString file);
+
+
+    /** @brief Set configuration file name
+     ** @param fileName  Configuration file name
+     **
+     ** Legacy interface for running from ROOT prompt. In the executable, the config is read in
+     ** by the application.
+     **/
+    void LoadConfig(const char* fileName);
+
+
+    /** @brief Set configuration
+     ** @param fileName  Configuration object
+     **/
+    void SetConfig(const Config& config) { fConfig = config; }
+
+
+    /** @brief Set geometry setup tag
+     ** @param tag  Geometry setup tag
+     **/
+    void SetGeoSetupTag(const char* tag) { fSetupTag = tag; }
+
+
+    /** @brief Set output file name
+     ** @param fileName  Output file name
+     **/
+    void SetOutput(const char* fileName) { fOutput = fileName; }
+
+
+    /** @brief Set transport file name
+     ** @param files  Transport input sources
+     **/
+    void SetTraFiles(const std::vector<std::string> files);
+
+
+    /** @brief Set parameter file name
+     ** @param fileName  Parameter file name
+     **/
+    void SetParFile(const char* fileName) { fPar = fileName; }
+
+
+   private:
+    /** @brief Copy constructor forbidden **/
+    Run(const Run&) = delete;
+
+
+    /** @brief Assignment operator forbidden **/
+    Run operator=(const Run&) = delete;
+
+
+    /** @brief Check existence of a file
+     ** @param fileName  File name (absolute or relative to current directory)
+     ** @return true if file exists
+     **/
+    bool CheckFile(const char* fileName);
+
+
+   private:
+    CbmDigitization fRun{};
+    TString fOutput = "";
+    std::vector<TString> fTra;
+    TString fPar      = "";
+    TString fSetupTag = "";
+    CbmSetup* fSetup  = nullptr;
+    bool fOverwrite   = false;
+
+   public:
+    Config fConfig = {};
+
+
+    ClassDef(cbm::sim::digitization::Run, 1);
+  };
+
+}  // namespace cbm::sim::digitization
+
+#endif /* CBMSIM_DIGITIZATION_STEER_RUN_H */