diff --git a/MQ/mcbm/CMakeLists.txt b/MQ/mcbm/CMakeLists.txt
index 0c6680cd22874e6e2fa57562e0eabe3cd024ffb1..98b51503f56525b0c12cdea75ca1f88ea6d2542d 100644
--- a/MQ/mcbm/CMakeLists.txt
+++ b/MQ/mcbm/CMakeLists.txt
@@ -3,15 +3,11 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startMQMcbmEvtBuilderWin2020.sh.in ${
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startMQBuildRawEvents.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startMQBuildRawEvents.sh)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startBuildRawEvents2021.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startBuildRawEvents2021.sh)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startBuildRawEventsCosmics2021.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startBuildRawEventsCosmics2021.sh)
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startEventBuilder.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startEventBuilder.sh)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/startBuildRawEvents2022.sh.in ${CMAKE_BINARY_DIR}/bin/MQ/topologies/startBuildRawEvents2022.sh)
 
 set(INCLUDE_DIRECTORIES
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${CMAKE_SOURCE_DIR}/MQ/base
-    ${CBMROOT_SOURCE_DIR}/algo
-    ${CBMROOT_SOURCE_DIR}/algo/evbuild
-    ${CBMROOT_SOURCE_DIR}/algo/trigger
     ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/unpacker
     ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/tasks
     ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/parameter
@@ -258,28 +254,6 @@ set(DEPENDENCIES
 )
 GENERATE_EXECUTABLE()
 
-set(EXE_NAME EventBuilder)
-set(SRCS CbmDeviceEventBuilder.cxx runEventBuilder.cxx)
-
-set(DEPENDENCIES
-  ${DEPENDENCIES_ALL}
-  Algo
-  CbmFlibFlesTools
-  CbmEventBuilder
-  KF
-  L1
-  CbmBase
-  CbmRecoBase
-  CbmData
-  CbmTofBase
-  Core
-  RIO
-  Net
-  Hist
-  RHTTP
-)
-GENERATE_EXECUTABLE()
-
 set(EXE_NAME DigiEventSink)
 set(SRCS CbmDeviceDigiEventSink.cxx runDigiEventSink.cxx)
 
@@ -299,26 +273,6 @@ set(DEPENDENCIES
 )
 GENERATE_EXECUTABLE()
 
-set(EXE_NAME EventSink)
-set(SRCS CbmDeviceEventSink.cxx runEventSink.cxx)
-
-set(DEPENDENCIES
-  ${DEPENDENCIES_ALL}
-  external::fles_ipc
-  CbmFlibMcbm2018
-  CbmFlibFlesTools
-  CbmBase
-  CbmData
-  Core
-  RIO
-  Tree
-  Net
-  Hist
-  RHTTP
-)
-GENERATE_EXECUTABLE()
-
-
 # Set the correct variables for the installation
 set(VMCWORKDIR ${CMAKE_INSTALL_PREFIX}/share/cbmroot)
 
@@ -334,13 +288,11 @@ configure_file(${MY_SOURCE_DIR}/startMQMcbmEvtBuilderWin2020.sh.in   ${TMPDIR}/b
 configure_file(${MY_SOURCE_DIR}/startMQBuildRawEvents.sh.in          ${TMPDIR}/bin/MQ/topologies/install/startMQBuildRawEvents.sh)
 configure_file(${MY_SOURCE_DIR}/startBuildRawEvents2021.sh.in        ${TMPDIR}/bin/MQ/topologies/install/startBuildRawEvents2021.sh)
 configure_file(${MY_SOURCE_DIR}/startBuildRawEventsCosmics2021.sh.in ${TMPDIR}/bin/MQ/topologies/install/startBuildRawEventsCosmics2021.sh)
-configure_file(${MY_SOURCE_DIR}/startEventBuilder.sh.in              ${TMPDIR}/bin/MQ/topologies/install/startEventBuilder.sh)
 
 install(PROGRAMS ${TMPDIR}/bin/MQ/topologies/install/startMQMcbmPulserMonitor2020.sh
                  ${TMPDIR}/bin/MQ/topologies/install/startMQMcbmEvtBuilderWin2020.sh
                  ${TMPDIR}/bin/MQ/topologies/install/startMQBuildRawEvents.sh
                  ${TMPDIR}/bin/MQ/topologies/install/startBuildRawEvents2021.sh
                  ${TMPDIR}/bin/MQ/topologies/install/startBuildRawEventsCosmics2021.sh
-                 ${TMPDIR}/bin/MQ/topologies/install/startEventBuilder.sh
         DESTINATION ${CMAKE_INSTALL_PREFIX}/bin/MQ/topologies
        )
diff --git a/MQ/mcbm/CbmDeviceEventBuilder.h b/MQ/mcbm/CbmDeviceEventBuilder.h
deleted file mode 100644
index 2f4ee1be5e0e86808ec9238fff427e301ae3e709..0000000000000000000000000000000000000000
--- a/MQ/mcbm/CbmDeviceEventBuilder.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Dominik Smith[committer] */
-
-/**
- * CbmDeviceEventBuilder.h
- *
- * @since 2022-02-01
- * @author D. Smith
- */
-
-#ifndef CBMDEVICEEVENTBUILDER_H_
-#define CBMDEVICEEVENTBUILDER_H_
-
-/// CBM headers
-#include "TimeClusterTrigger.h"
-
-#include "EventBuilder.h"
-
-/// FAIRROOT headers
-#include "FairMQDevice.h"
-
-/// FAIRSOFT headers (geant, boost, ...)
-#include "Rtypes.h"
-#include "TObjArray.h"
-
-/// C/C++ headers
-#include <chrono>
-#include <vector>
-
-class CbmTsEventHeader;
-
-class FairRunOnline;
-class FairRootManager;
-
-class TClonesArray;
-class TimesliceMetaData;
-
-class CbmDeviceEventBuilder : public FairMQDevice {
-public:
-  CbmDeviceEventBuilder();
-  virtual ~CbmDeviceEventBuilder();
-
-protected:
-  virtual void InitTask();
-  bool HandleData(FairMQParts&, int);
-  bool HandleCommand(FairMQMessagePtr&, int);
-
-private:
-  Bool_t fbFinishDone = false;  //! Keep track of whether the Finish was already called
-
-  /// Constants
-
-  /// Control flags
-  //Bool_t fbIgnoreTsOverlap = kFALSE;  //! Ignore data in Overlap part of the TS
-  //Bool_t fbFillHistos      = kTRUE;   //! Switch ON/OFF filling of histograms
-
-  /// User settings parameters
-  /// Algo enum settings
-  ECbmModuleId fTriggerDet = ECbmModuleId::kT0;
-
-  /// message queues
-  std::string fsChannelNameDataInput   = "unpts_0";
-  std::string fsChannelNameDataOutput  = "events";
-  std::string fsChannelNameCommands    = "commands";
-  std::string fsChannelNameHistosInput = "histogram-in";
-  /// Histograms management
-  uint32_t fuPublishFreqTs  = 100;
-  double_t fdMinPublishTime = 0.5;
-  double_t fdMaxPublishTime = 5.0;
-
-  /// List of MQ channels names
-  std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
-
-  /// Statistics & first TS rejection
-  uint64_t fulNumMessages                                = 0;
-  uint64_t fulTsCounter                                  = 0;
-  std::chrono::system_clock::time_point fLastPublishTime = std::chrono::system_clock::now();
-
-  /// Processing algos
-  cbm::algo::TimeClusterTrigger fTriggerAlgo;
-  cbm::algo::EventBuilder fEvbuildAlgo;
-
-  // Trigger algorithm params
-  double fTriggerWindow = 0.;
-  int32_t fMinNumDigis  = 0;
-  double fDeadTime      = 0.;
-
-  /// Data storage
-  std::string fsOutputFileName             = "";
-  FairRunOnline* fpRun                     = nullptr;
-  FairRootManager* fpFairRootMgr           = nullptr;
-  CbmTsEventHeader* fCbmTsEventHeaderOut   = nullptr;  // output container for TS information in header
-  std::vector<CbmDigiEvent>* fEventsSelOut = nullptr;  // output container of CbmDigiEvents
-  TClonesArray* fTimeSliceMetaDataArrayOut = nullptr;  // output container of meta data
-
-  bool IsChannelNameAllowed(std::string channelName);
-  bool SendEvents(const std::vector<CbmDigiEvent>& vEvents, const TimesliceMetaData* tsMetaData,
-                  const CbmTsEventHeader* eventHeader);
-
-  // --- Extract digi times into to a vector
-  template<class TDigi>
-  std::vector<double> GetDigiTimes(const std::vector<TDigi>& digiVec)
-  {
-    std::vector<double> digiTimes(digiVec.size());
-    std::transform(digiVec.begin(), digiVec.end(), digiTimes.begin(), [](const TDigi& digi) { return digi.GetTime(); });
-    return digiTimes;
-  }
-
-  // Get trigger times using trigger algorithm
-  std::vector<double> GetTriggerTimes(const CbmDigiTimeslice& ts);
-
-  // Get detector type from string containing name
-  ECbmModuleId GetDetectorId(std::string detName);
-
-  void DumpTreeEntry();
-  void Finish();
-};
-
-#endif /* CBMDEVICEEVENTBUILDER_H_ */
diff --git a/MQ/mcbm/runEventBuilder.cxx b/MQ/mcbm/runEventBuilder.cxx
deleted file mode 100644
index 28c46e970f3dfad43b0c1b04ee00f7d7a1673a1e..0000000000000000000000000000000000000000
--- a/MQ/mcbm/runEventBuilder.cxx
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Dominik Smith [committer] */
-
-#include "CbmDeviceEventBuilder.h"
-
-#include <iomanip>
-#include <string>
-
-#include "runFairMQDevice.h"
-
-namespace bpo = boost::program_options;
-using namespace std;
-
-void addCustomOptions(bpo::options_description& options)
-{
-  options.add_options()("TriggerWin", bpo::value<double>()->default_value(0.0), "Time window for trigger algorithm");
-  options.add_options()("TriggerMinDigis", bpo::value<int32_t>()->default_value(1),
-                        "Minimum digi count for trigger algorithm");
-  options.add_options()("TriggerDeadTime", bpo::value<double>()->default_value(0.0), "Dead time for trigger algorithm");
-  options.add_options()("FillHistos", bpo::value<bool>()->default_value(true),
-                        "Fill histograms and send them to histo server if true");
-  options.add_options()("IgnTsOver", bpo::value<bool>()->default_value(false), "Ignore TS overlap if true");
-  options.add_options()("OutFileName", bpo::value<std::string>()->default_value(""),
-                        "Name (full or relative path) of the output .root file ");
-  options.add_options()("TriggerDet", bpo::value<std::string>()->default_value("kT0"),
-                        "Set the trigger detector, use string matching an ECbmModuleId ");
-  options.add_options()("AddDet", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
-                        "Add a detector for digis selection, use string matching an ECbmModuleId ");
-  options.add_options()("SetEvbuildWin", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
-                        "Set event builder window for selected detector, use string matching "
-                        "ECbmModuleId,dWinBeg,dWinEnd e.g. kSts,-10.5,100.0");
-  options.add_options()("TsNameIn", bpo::value<std::string>()->default_value("unpts_0"),
-                        "MQ channel name for unpacked TS data");
-  options.add_options()("EvtNameOut", bpo::value<std::string>()->default_value("events"),
-                        "MQ channel name for built events");
-  options.add_options()("ChNameIn", bpo::value<std::string>()->default_value("histogram-in"),
-                        "MQ channel name for histos");
-  options.add_options()("ChNameHistCfg", bpo::value<std::string>()->default_value("histo-conf"),
-                        "MQ channel name for histos config");
-  options.add_options()("ChNameCanvCfg", bpo::value<std::string>()->default_value("canvas-conf"),
-                        "MQ channel name for canvases config");
-  options.add_options()("PubFreqTs", bpo::value<uint32_t>()->default_value(100), "Histo publishing frequency in TS");
-  options.add_options()("PubTimeMin", bpo::value<double_t>()->default_value(1.0),
-                        "Minimal time between two publishing");
-  options.add_options()("PubTimeMax", bpo::value<double_t>()->default_value(10.0),
-                        "Maximal time between two publishing");
-}
-
-FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDeviceEventBuilder(); }
diff --git a/MQ/mcbm/startEventBuilder.sh.in b/MQ/mcbm/startEventBuilder.sh.in
deleted file mode 100755
index 195f78f8d7804c5b7804b0a02d08ce8e07f243d4..0000000000000000000000000000000000000000
--- a/MQ/mcbm/startEventBuilder.sh.in
+++ /dev/null
@@ -1,253 +0,0 @@
-#!/bin/bash
-
-if [ -e @SIMPATH@/bin/fairmq-shmmonitor ]; then
-  @SIMPATH@/bin/fairmq-shmmonitor --cleanup
-fi
-
-if [ $# -ge 1 ]; then
-  _nbmoni=$1
-  ((_pubfreqts = $_nbmoni*100 ))
-  _pubminsec=1.0
-  _pubmaxsec=10.0
-
-  if [ $# -ge 4 ]; then
-    _filename=""
-    _dirname=""
-    _hostname=$4
-
-    if [ $# -ge 5 ]; then
-      _pubfreqts=$5
-
-      if [ $# -ge 6 ]; then
-        _pubminsec=$6
-
-        if [ $# -ge 7 ]; then
-          _pubmaxsec=$7
-        fi
-      fi
-    fi
-  elif [ $# -ge 2 ]; then
-    _filename=$2
-    _hostname=""
-    if [ $# -eq 3 ]; then
-      _dirname=$3
-    else
-      _dirname=""
-    fi
-  else
-    echo 'Starting connection to local stream'
-    echo ' for other usages, please supply at least a filename.'
-    echo 'Possible usages are:'
-    echo 'startMQMcbmPulserMonitor2020.sh'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <full filename pattern list>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <filename pattern> <folder_path>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s> <Max Hist pub. in s>'
-    _filename=""
-    _dirname=""
-    _hostname="localhost"
-  fi
-else
-  echo 'Starting connection to local stream with 1 monitor process'
-  echo ' for other usages, please supply at least a filename.'
-  echo 'Possible usages are:'
-  echo 'startMQMcbmPulserMonitor2020.sh'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <full filename pattern list>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <filename pattern> <folder_path>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s> <Max Hist pub. in s>'
-  _filename=""
-  _dirname=""
-  _hostname="localhost"
-  _nbmoni=1
-  _pubfreqts=100
-  _pubminsec=1.0
-  _pubmaxsec=10.0
-fi
-
-_parfileSts=@VMCWORKDIR@/macro/beamtime/mcbm2021/mStsPar.par
-_parfileMuch=@VMCWORKDIR@/macro/beamtime/mcbm2021/mMuchPar.par
-_parfileTrdAsic=@VMCWORKDIR@/parameters/trd/trd_v21b_mcbm.asic.par
-_parfileTrdDigi=@VMCWORKDIR@/parameters/trd/trd_v21b_mcbm.digi.par
-_parfileTrdGas=@VMCWORKDIR@/parameters/trd/trd_v21b_mcbm.gas.par
-_parfileTrdGain=@VMCWORKDIR@/parameters/trd/trd_v21b_mcbm.gain.par
-_parfileTof=@VMCWORKDIR@/macro/beamtime/mcbm2021/mTofCriPar.par
-_parfileRich=@VMCWORKDIR@/macro/beamtime/mcbm2021/mRichPar_70.par
-_parfilePsd=@VMCWORKDIR@/macro/beamtime/mcbm2021/mPsdPar.par
-_setup_name=mcbm_beam_2021_07_surveyed
-_run_id=1588
-
-LOGFILETAG=`hostname`
-LOGFILETAG+="_"
-LOGFILETAG+=`date +%Y_%m_%d_%H_%M_%S`
-LOGFILETAG+=".log"
-
-(( _paraBuffSz=100 ))
-(( _singBuffSz=_paraBuffSz*_nbmoni ))
-
-echo "Buffer size for parallel  devices $_paraBuffSz"
-echo "Buffer size for singleton devices $_singBuffSz"
-
-SAMPLER="RepReqTsSampler"
-SAMPLER+=" --id sampler1"
-#SAMPLER+=" --max-timeslices 0"
-#SAMPLER+=" --max-timeslices 10"
-#SAMPLER+=" --max-timeslices 100"
-SAMPLER+=" --max-timeslices 300"
-#SAMPLER+=" --max-timeslices 1000"
-SAMPLER+=" --severity info"
-#SAMPLER+=" --flib-port 10"
-if [ "$_hostname" != "" ]; then
-  SAMPLER+=" --fles-host $_hostname"
-elif [ "$_filename" != "" ]; then
-  SAMPLER+=" --filename $_filename"
-  if [ "$_dirname" != "" ]; then
-    SAMPLER+=" --dirname $_dirname"
-  fi
-fi
-SAMPLER+=" --high-water-mark 1000"
-SAMPLER+=" --no-split-ts 1"
-SAMPLER+=" --ChNameMissTs missedts"
-SAMPLER+=" --ChNameCmds commands"
-SAMPLER+=" --PubFreqTs $_pubfreqts"
-SAMPLER+=" --PubTimeMin $_pubminsec"
-SAMPLER+=" --PubTimeMax $_pubmaxsec"
-SAMPLER+=" --channel-config name=ts-request,type=rep,method=bind,transport=zeromq,address=tcp://127.0.0.1:11555"
-SAMPLER+=" --channel-config name=histogram-in,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11666"
-SAMPLER+=" --channel-config name=missedts,type=pub,method=bind,address=tcp://127.0.0.1:11006"
-SAMPLER+=" --channel-config name=commands,type=pub,method=bind,address=tcp://127.0.0.1:11007"
-SAMPLER+=" --transport zeromq"
-# Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
-# with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
-SAMPLER_LOG="sampler1_$LOGFILETAG"
-xterm -l -lf $SAMPLER_LOG -geometry 80x23+0+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/source/$SAMPLER  &
-
-echo $SAMPLER
-
-_iMoni=0
-while (( _iMoni < _nbmoni )); do
-  (( _yOffset=200*_iMoni ))
-  (( _iMoni += 1 ))
-  (( _iPort = 11680 + _iMoni ))
-
-  UNPACKER="MqUnpack"
-  UNPACKER+=" --id unp$_iMoni"
-  UNPACKER+=" --severity info"
-  #UNPACKER+=" --severity debug"
-  UNPACKER+=" --Setup $_setup_name"
-  UNPACKER+=" --RunId $_run_id"
-  UNPACKER+=" --IgnOverMs 1"
-  UNPACKER+=" --SetTimeOffs kSTS,-2221"
-  UNPACKER+=" --SetTimeOffs kMUCH,-885"
-  UNPACKER+=" --SetTimeOffs kTRD,0"
-  UNPACKER+=" --SetTimeOffs kTRD2D,-1800"
-  UNPACKER+=" --SetTimeOffs kTOF,-1220"
-  UNPACKER+=" --SetTimeOffs kRICH,254800"
-  UNPACKER+=" --SetTimeOffs kPSD,0"
-  UNPACKER+=" --PubFreqTs $_pubfreqts"
-  UNPACKER+=" --PubTimeMin $_pubminsec"
-  UNPACKER+=" --PubTimeMax $_pubmaxsec"
-  UNPACKER+=" --TsNameOut unpts$_iMoni"
-  UNPACKER+=" --channel-config name=ts-request,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11555"
-  UNPACKER+=" --channel-config name=parameters,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11005,rateLogging=0"
-  UNPACKER+=" --channel-config name=unpts$_iMoni,type=push,method=bind,transport=zeromq,address=tcp://127.0.0.1:$_iPort"
-#  UNPACKER+=" --channel-config name=commands,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11007"
-  UNPACKER+=" --channel-config name=histogram-in,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11666"
-  UNPACKER+=" --transport zeromq"
-  # Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
-  # with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
-  UNPACKER_LOG="unp$_iMoni"
-  UNPACKER_LOG+="_$LOGFILETAG"
-  xterm -l -lf $UNPACKER_LOG -geometry 132x23+400+$_yOffset -hold -e @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$UNPACKER &
-
-  EVTBUILDER="EventBuilder"
-  EVTBUILDER+=" --id build$_iMoni"
-  EVTBUILDER+=" --severity info"
-  #EVTBUILDER+=" --severity debug"
-  EVTBUILDER+=" --PubFreqTs $_pubfreqts"
-  EVTBUILDER+=" --PubTimeMin $_pubminsec"
-  EVTBUILDER+=" --PubTimeMax $_pubmaxsec"
-  EVTBUILDER+=" --FillHistos true"
-  EVTBUILDER+=" --OutFileName events.root"
-  EVTBUILDER+=" --IgnTsOver false"
-  EVTBUILDER+=" --TriggerDet kTof"
-  EVTBUILDER+=" --TriggerWin 0.0"
-  EVTBUILDER+=" --TriggerMinDigis 1"
-  EVTBUILDER+=" --TriggerDeadTime 0.0"
-  EVTBUILDER+=" --AddDet kSts"
-  EVTBUILDER+=" --AddDet kTrd"
-  EVTBUILDER+=" --AddDet kTof"
-  EVTBUILDER+=" --AddDet kRich"
-  EVTBUILDER+=" --AddDet kPsd"
-  EVTBUILDER+=" --SetEvbuildWin kSts,-100,100"
-  EVTBUILDER+=" --SetEvbuildWin kTrd,-250,250"
-  EVTBUILDER+=" --SetEvbuildWin kTof,-150,150" # To get T0 Digis (seed + close-by digis) in the event
-  EVTBUILDER+=" --SetEvbuildWin kRich,-100,100"
-  EVTBUILDER+=" --SetEvbuildWin kPsd,-100,100"
-  EVTBUILDER+=" --TsNameIn unpts$_iMoni"
-  EVTBUILDER+=" --EvtNameOut events"
-  EVTBUILDER+=" --channel-config name=unpts$_iMoni,type=pull,method=connect,transport=zeromq,address=tcp://127.0.0.1:$_iPort"
-  EVTBUILDER+=" --channel-config name=events,type=push,method=connect,transport=zeromq,address=tcp://127.0.0.1:11556"
-#  EVTBUILDER+=" --channel-config name=commands,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11007"
-  EVTBUILDER+=" --channel-config name=parameters,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11005,rateLogging=0"
-  EVTBUILDER+=" --channel-config name=histogram-in,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11666"
-  EVTBUILDER+=" --transport zeromq"
-  # Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
-  # with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
-  EVTBUILDER_LOG="build$_iMoni"
-  EVTBUILDER_LOG+="_$LOGFILETAG"
-  xterm -l -lf $EVTBUILDER_LOG -geometry 80x23+800+$_yOffset -hold -e @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$EVTBUILDER &
-
-done
-
-EVTSINK="EventSink"
-EVTSINK+=" --id evtsink1"
-EVTSINK+=" --severity info"
-#EVTSINK+=" --severity debug"
-#EVTSINK+=" --StoreFullTs 1"
-EVTSINK+=" --OutFileName mcbm_digis_events.root"
-EVTSINK+=" --FillHistos false"
-EVTSINK+=" --PubFreqTs $_pubfreqts"
-EVTSINK+=" --PubTimeMin $_pubminsec"
-EVTSINK+=" --PubTimeMax $_pubmaxsec"
-EVTSINK+=" --EvtNameIn events"
-EVTSINK+=" --channel-config name=events,type=pull,method=bind,transport=zeromq,address=tcp://127.0.0.1:11556"
-EVTSINK+=" --channel-config name=missedts,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11006"
-EVTSINK+=" --channel-config name=commands,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11007"
-EVTSINK+=" --channel-config name=histogram-in,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11666"
-# Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
-# with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
-EVTSINK_LOG="evtsink1_$LOGFILETAG"
-xterm -l -lf $EVTSINK_LOG -geometry 80x23+1200+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$EVTSINK &
-
-PARAMETERSERVER="parmq-server"
-PARAMETERSERVER+=" --id parmq-server"
-PARAMETERSERVER+=" --severity info"
-PARAMETERSERVER+=" --channel-name parameters"
-PARAMETERSERVER+=" --channel-config name=parameters,type=rep,method=bind,transport=zeromq,address=tcp://127.0.0.1:11005,rateLogging=0"
-PARAMETERSERVER+=" --first-input-name $_parfileSts;$_parfileMuch;$_parfileTrdAsic;$_parfileTrdDigi;$_parfileTrdGas;$_parfileTrdGain;$_parfileTof;$_parfileRich;$_parfilePsd"
-PARAMETERSERVER+=" --first-input-type ASCII"
-PARAMETERSERVER+=" --libs-to-load=libCbmFlibMcbm2018" # doesn't work due to runtime problem
-PARAMETERSERVER+=" --setup $_setup_name"
-# Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
-# with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
-PARAMSRV_LOG="parmq_$LOGFILETAG"
-xterm -l -lf $PARAMSRV_LOG -geometry 80x23+1600+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/parmq/$PARAMETERSERVER &
-
-HISTSERVER="MqHistoServer"
-HISTSERVER+=" --id server1"
-HISTSERVER+=" --severity info"
-HISTSERVER+=" --histport 8081"
-HISTSERVER+=" --channel-config name=histogram-in,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11666"
-HISTSERVER+=" --channel-config name=histo-conf,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11667,rateLogging=0"
-HISTSERVER+=" --channel-config name=canvas-conf,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11668,rateLogging=0"
-# Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
-# with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
-HISTSRV_LOG="server1_$LOGFILETAG"
-xterm -l -lf $HISTSRV_LOG -geometry 80x23+2000+0 -hold -e @CMAKE_BINARY_DIR@/bin/MQ/histogramServer/$HISTSERVER &
diff --git a/reco/CMakeLists.txt b/reco/CMakeLists.txt
index a2b6cd17bc43e259e4b7113b2aef7d157a7c35a0..ec5b6e588c586a47b6e2972cbbcda2d2b8da0719 100644
--- a/reco/CMakeLists.txt
+++ b/reco/CMakeLists.txt
@@ -15,3 +15,4 @@ add_subdirectory(qa)
 add_subdirectory (tasks)
 add_subdirectory (app)
 add_subdirectory (mq)
+
diff --git a/reco/mq/CMakeLists.txt b/reco/mq/CMakeLists.txt
index 8334c0263ba87cb3070e3761c7716fd05a08d088..035786646b130aef40b135f60da6543e48e00a08 100644
--- a/reco/mq/CMakeLists.txt
+++ b/reco/mq/CMakeLists.txt
@@ -35,6 +35,7 @@ Set(SYSTEM_INCLUDE_DIRECTORIES
     ${FAIRROOT_INCLUDE_DIR}
     ${FAIRMQ_INCLUDE_DIR}
     ${FAIRMQ_INCLUDE_DIR}/options
+    ${VMC_INCLUDE_DIRS}
     ${FAIRLOGGER_INCLUDE_DIR}
 
     ${IPC_INCLUDE_DIRECTORY}
@@ -45,7 +46,6 @@ include_directories(${INCLUDE_DIRECTORIES})
 include_directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
 
 set(LINK_DIRECTORIES
-  ${KFParticle_LIB_DIR}
   ${FAIRMQ_LIBRARY_DIR}
   ${FAIRROOT_LIBRARY_DIR}
   ${ROOT_LIBRARY_DIR}
@@ -54,9 +54,9 @@ set(LINK_DIRECTORIES
 
 link_directories(${LINK_DIRECTORIES})
 
-# Set the install path within the build directory
+#Set the install path within the build directory
 set(EXECUTABLE_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}/mq")
-# Set the install path within the installation directory
+#Set the install path within the installation directory
 set(BIN_DESTINATION bin/mq)
 
 Set(BOOST_LIBS
@@ -84,26 +84,60 @@ set(EXE_NAME MqDevUnpack)
 set(SRCS CbmDevUnpack.cxx runUnpack.cxx)
 
 set(DEPENDENCIES
-  ${DEPENDENCIES}
   ${FAIR_LIBS}
   ${BOOST_LIBS}
   external::fles_ipc
-  CbmFlibFlesTools
   Algo
-  CbmBase
-  CbmRecoBase
-  CbmPsdReco
-  CbmRichReco
-  CbmRecoSts
-  CbmTofReco
-  CbmTrdReco
   CbmData
-  CbmSimSteer # for CbmSetup!
   Core
+  RIO
+  Net
+)
+GENERATE_EXECUTABLE()
+
+set(EXE_NAME MqDevTrigger)
+set(SRCS CbmDevTrigger.cxx runTrigger.cxx)
+
+set(DEPENDENCIES
+  ${FAIR_LIBS}
+  ${BOOST_LIBS}
+  Algo
+  CbmData
+  Core
+  RIO
+  Net
+)
+GENERATE_EXECUTABLE()
+
+set(EXE_NAME MqDevBuildEvents)
+set(SRCS CbmDevBuildEvents.cxx runBuildEvents.cxx)
+
+set(DEPENDENCIES
+  ${FAIR_LIBS}
+  ${BOOST_LIBS}
+  Algo
+  CbmData
+  Core
+  RIO
+  Net
+)
+GENERATE_EXECUTABLE()
+
+set(EXE_NAME MqDevEventSink)
+set(SRCS CbmDevEventSink.cxx runEventSink.cxx)
+
+set(DEPENDENCIES
+  ${FAIR_LIBS}
+  ${BOOST_LIBS}
+  CbmFlibFlesTools
+  CbmData
+  Core
+  RIO
+  Net
 )
 GENERATE_EXECUTABLE()
 
-# Set the correct variables for the installation
+#Set the correct variables for the installation
 set(VMCWORKDIR ${CMAKE_INSTALL_PREFIX}/share/cbmroot)
 
 set(MY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
@@ -112,7 +146,7 @@ set(CMAKE_CURRENT_SOURCE_DIR ${VMCWORKDIR}/input)
 set(TMPDIR "${CMAKE_BINARY_DIR}")
 set(CMAKE_BINARY_DIR ${CMAKE_INSTALL_PREFIX})
 
-# Configure file for installation directory
+#Configure file for installation directory
 configure_file(${MY_SOURCE_DIR}/startUnpack.sh.in              ${TMPDIR}/bin/MQ/topologies/install/startUnpack.sh)
 
 install(PROGRAMS ${TMPDIR}/bin/MQ/topologies/install/startUnpack.sh
diff --git a/MQ/mcbm/CbmDeviceEventBuilder.cxx b/reco/mq/CbmDevBuildEvents.cxx
similarity index 57%
rename from MQ/mcbm/CbmDeviceEventBuilder.cxx
rename to reco/mq/CbmDevBuildEvents.cxx
index 37a7a2e9bec0c2dd282e4eb99c6018822f8a66fb..010a835406483d64c492ff1fa8d0e38d7ec22870 100644
--- a/MQ/mcbm/CbmDeviceEventBuilder.cxx
+++ b/reco/mq/CbmDevBuildEvents.cxx
@@ -2,20 +2,14 @@
    SPDX-License-Identifier: GPL-3.0-only
    Authors: Pierre-Alain Loizeau[committer], Dominik Smith */
 
-#include "CbmDeviceEventBuilder.h"
+#include "CbmDevBuildEvents.h"
 
 /// CBM headers
-#include "CbmEvent.h"
-#include "CbmFlesCanvasTools.h"
 #include "CbmMQDefs.h"
-#include "CbmMatch.h"
-#include "CbmMvdDigi.h"
-#include "CbmTsEventHeader.h"
 
 /// FAIRROOT headers
 #include "FairMQLogger.h"
-#include "FairMQProgOptions.h"  // device->fConfig
-#include "FairParGenericSet.h"
+#include "FairMQProgOptions.h"
 #include "FairRootFileSink.h"
 #include "FairRootManager.h"
 #include "FairRunOnline.h"
@@ -27,13 +21,6 @@
 /// FAIRSOFT headers (geant, boost, ...)
 #include "TimesliceMetaData.h"
 
-#include "TCanvas.h"
-#include "TClonesArray.h"
-#include "TFile.h"
-#include "TH1.h"
-#include "TList.h"
-#include "TNamed.h"
-
 #include <boost/archive/binary_iarchive.hpp>
 #include <boost/serialization/utility.hpp>
 
@@ -48,35 +35,21 @@ struct InitTaskError : std::runtime_error {
 
 using namespace std;
 
-CbmDeviceEventBuilder::CbmDeviceEventBuilder() {}
+CbmDevBuildEvents::CbmDevBuildEvents() {}
 
-void CbmDeviceEventBuilder::InitTask()
+void CbmDevBuildEvents::InitTask()
 try {
   /// Read options from executable
-  LOG(info) << "Init options for CbmDeviceEventBuilder.";
-  //fbFillHistos      = fConfig->GetValue<bool>("FillHistos");
-  //fbIgnoreTsOverlap = fConfig->GetValue<bool>("IgnOverMs");
+  LOG(info) << "Init options for CbmDevBuildEvents.";
 
   fsOutputFileName = fConfig->GetValue<std::string>("OutFileName");  //For storage of events
 
   // Event builder algorithm params
-  const std::vector<std::string> vsAddDet        = fConfig->GetValue<std::vector<std::string>>("AddDet");
   const std::vector<std::string> vsSetEvbuildWin = fConfig->GetValue<std::vector<std::string>>("SetEvbuildWin");
 
-  // Trigger algorithm params
-  const std::string sTriggerDet = fConfig->GetValue<std::string>("TriggerDet");
-  fTriggerWindow                = fConfig->GetValue<double>("TriggerWin");
-  fMinNumDigis                  = fConfig->GetValue<int32_t>("TriggerMinDigis");
-  fDeadTime                     = fConfig->GetValue<double>("TriggerDeadTime");
-
-  fsChannelNameDataInput   = fConfig->GetValue<std::string>("TsNameIn");
-  fsChannelNameDataOutput  = fConfig->GetValue<std::string>("EvtNameOut");
-  fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
-  fsAllowedChannels[0]     = fsChannelNameDataInput;
-
-  fuPublishFreqTs  = fConfig->GetValue<uint32_t>("PubFreqTs");
-  fdMinPublishTime = fConfig->GetValue<double_t>("PubTimeMin");
-  fdMaxPublishTime = fConfig->GetValue<double_t>("PubTimeMax");
+  fsChannelNameDataInput  = fConfig->GetValue<std::string>("TrigNameIn");
+  fsChannelNameDataOutput = fConfig->GetValue<std::string>("EvtNameOut");
+  fsAllowedChannels[0]    = fsChannelNameDataInput;
 
   /// Prepare root output
   if ("" != fsOutputFileName) {
@@ -88,9 +61,6 @@ try {
     fpFairRootMgr->InitSink();
 
     /// Create storage objects
-    fCbmTsEventHeaderOut = new CbmTsEventHeader();
-    fpFairRootMgr->Register("EventHeader.", "Event", fCbmTsEventHeaderOut, kTRUE);
-
     fEventsSelOut = new std::vector<CbmDigiEvent>();
     fpFairRootMgr->RegisterAny("DigiEvent", fEventsSelOut, kTRUE);
 
@@ -115,39 +85,16 @@ try {
     LOG(info) << "Channel name: " << entry.first;
     if (std::string::npos != entry.first.find(fsChannelNameDataInput)) {
       if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
-      OnData(entry.first, &CbmDeviceEventBuilder::HandleData);
-    }
-  }
-
-  /// Extract refdet
-  fTriggerDet = GetDetectorId(sTriggerDet);
-
-  if (ECbmModuleId::kNotExist == fTriggerDet) {
-    LOG(info) << "CbmDeviceEventBuilder::InitTask => Trying to change "
-                 "reference to unsupported detector, ignored! "
-              << sTriggerDet;
-  }
-
-  /// Extract detector to add if any
-  /*
-  for (std::vector<std::string>::const_iterator itStrAdd = vsAddDet.begin(); itStrAdd != vsAddDet.end(); ++itStrAdd) {
-    const ECbmModuleId addDet = GetDetectorId(*itStrAdd);
-    if (ECbmModuleId::kNotExist != addDet) { fEvbuildAlgo.AddSystem(addDet); }
-    else {
-      LOG(info) << "CbmDeviceEventBuilder::InitTask => Trying to add "
-                   "unsupported detector, ignored! "
-                << (*itStrAdd);
-      continue;
+      OnData(entry.first, &CbmDevBuildEvents::HandleData);
     }
   }
-  */
 
   /// Extract event builder window to add if any
   for (std::vector<std::string>::const_iterator itStrEvbuildWin = vsSetEvbuildWin.begin();
        itStrEvbuildWin != vsSetEvbuildWin.end(); ++itStrEvbuildWin) {
     size_t charPosDel = (*itStrEvbuildWin).find(',');
     if (std::string::npos == charPosDel) {
-      LOG(info) << "CbmDeviceEventBuilder::InitTask => "
+      LOG(info) << "CbmDevBuildEvents::InitTask => "
                 << "Trying to set event builder window with invalid option pattern, ignored! "
                 << " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found " << (*itStrEvbuildWin) << " )";
       continue;
@@ -158,7 +105,7 @@ try {
     const ECbmModuleId selDet = GetDetectorId(sSelDet);
 
     if (ECbmModuleId::kNotExist == selDet) {
-      LOG(info) << "CbmDeviceEventBuilder::InitTask => "
+      LOG(info) << "CbmDevBuildEvents::InitTask => "
                 << "Trying to set trigger window for unsupported detector, ignored! " << sSelDet;
       continue;
     }
@@ -168,7 +115,7 @@ try {
     std::string sNext = (*itStrEvbuildWin).substr(charPosDel);
     charPosDel        = sNext.find(',');
     if (std::string::npos == charPosDel) {
-      LOG(info) << "CbmDeviceEventBuilder::InitTask => "
+      LOG(info) << "CbmDevBuildEvents::InitTask => "
                 << "Trying to set event builder window with invalid option pattern, ignored! "
                 << " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found " << (*itStrEvbuildWin) << " )";
       continue;
@@ -188,7 +135,7 @@ catch (InitTaskError& e) {
   cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
 }
 
-ECbmModuleId CbmDeviceEventBuilder::GetDetectorId(std::string detName)
+ECbmModuleId CbmDevBuildEvents::GetDetectorId(std::string detName)
 {
   /// FIXME: Disable clang formatting for now as it corrupts all alignment
   /* clang-format off */
@@ -205,7 +152,7 @@ ECbmModuleId CbmDeviceEventBuilder::GetDetectorId(std::string detName)
   /* clang-format on */
 }
 
-bool CbmDeviceEventBuilder::IsChannelNameAllowed(std::string channelName)
+bool CbmDevBuildEvents::IsChannelNameAllowed(std::string channelName)
 {
   for (auto const& entry : fsAllowedChannels) {
     std::size_t pos1 = channelName.find(entry);
@@ -224,7 +171,7 @@ bool CbmDeviceEventBuilder::IsChannelNameAllowed(std::string channelName)
 }
 
 // handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
-bool CbmDeviceEventBuilder::HandleData(FairMQParts& parts, int /*index*/)
+bool CbmDevBuildEvents::HandleData(FairMQParts& parts, int /*index*/)
 {
   fulNumMessages++;
   LOG(info) << "Received message number " << fulNumMessages << " with " << parts.Size() << " parts"
@@ -235,69 +182,27 @@ bool CbmDeviceEventBuilder::HandleData(FairMQParts& parts, int /*index*/)
   /// Extract unpacked data from input message
   uint32_t uPartIdx = 0;
 
-  /// TS header
-  CbmTsEventHeader* evtHeader = new CbmTsEventHeader();
-  //  Deserialize<RootSerializer>(*parts.At(uPartIdx), evtHeader);
-  RootSerializer().Deserialize(*parts.At(uPartIdx), evtHeader);
-  ++uPartIdx;
-
+  /// TS
   CbmDigiTimeslice ts;
-
-  /// T0
-  std::string msgStrT0(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
-  std::istringstream issT0(msgStrT0);
-  boost::archive::binary_iarchive inputArchiveT0(issT0);
-  inputArchiveT0 >> ts.fData.fT0.fDigis;
-  ++uPartIdx;
-
-  /// STS
-  std::string msgStrSts(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
-  std::istringstream issSts(msgStrSts);
-  boost::archive::binary_iarchive inputArchiveSts(issSts);
-  inputArchiveSts >> ts.fData.fSts.fDigis;
-  ++uPartIdx;
-
-  /// MUCH
-  std::string msgStrMuch(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
-  std::istringstream issMuch(msgStrMuch);
-  boost::archive::binary_iarchive inputArchiveMuch(issMuch);
-  inputArchiveMuch >> ts.fData.fMuch.fDigis;
-  ++uPartIdx;
-
-  /// TRD
-  std::string msgStrTrd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
-  std::istringstream issTrd(msgStrTrd);
-  boost::archive::binary_iarchive inputArchiveTrd(issTrd);
-  inputArchiveTrd >> ts.fData.fTrd.fDigis;
-  ++uPartIdx;
-
-  /// T0F
-  std::string msgStrTof(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
-  std::istringstream issTof(msgStrTof);
-  boost::archive::binary_iarchive inputArchiveTof(issTof);
-  inputArchiveTof >> ts.fData.fTof.fDigis;
-  ++uPartIdx;
-
-  /// RICH
-  std::string msgStrRich(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
-  std::istringstream issRich(msgStrRich);
-  boost::archive::binary_iarchive inputArchiveRich(issRich);
-  inputArchiveRich >> ts.fData.fRich.fDigis;
-  ++uPartIdx;
-
-  /// PSD
-  std::string msgStrPsd(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
-  std::istringstream issPsd(msgStrPsd);
-  boost::archive::binary_iarchive inputArchivePsd(issPsd);
-  inputArchivePsd >> ts.fData.fPsd.fDigis;
+  std::string msgStrTS(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
+  std::istringstream issTS(msgStrTS);
+  boost::archive::binary_iarchive inputArchiveTS(issTS);
+  inputArchiveTS >> ts;
   ++uPartIdx;
 
   /// TS metadata
   TimesliceMetaData* tsMetaData = new TimesliceMetaData();
-  //  Deserialize<RootSerializer>(*parts.At(uPartIdx), tsMetaData);
   RootSerializer().Deserialize(*parts.At(uPartIdx), tsMetaData);
   ++uPartIdx;
 
+  /// Triggers
+  std::vector<double> triggers;
+  std::string msgStrTrig(static_cast<char*>(parts.At(uPartIdx)->GetData()), (parts.At(uPartIdx))->GetSize());
+  std::istringstream issTrig(msgStrTrig);
+  boost::archive::binary_iarchive inputArchiveTrig(issTrig);
+  inputArchiveTrig >> triggers;
+  ++uPartIdx;
+
   //if (1 == fulNumMessages) {
   /// First message received (do TS metadata stuff here)
   //fpAlgo->SetTsParameters(0, fTsMetaDataOut->GetDuration(), fTsMetaDataOut->GetOverlapDuration());
@@ -310,8 +215,6 @@ bool CbmDeviceEventBuilder::HandleData(FairMQParts& parts, int /*index*/)
   LOG(debug) << "TOF Vector size: " << ts.fData.fTof.fDigis.size();
   LOG(debug) << "RICH Vector size: " << ts.fData.fRich.fDigis.size();
   LOG(debug) << "PSD Vector size: " << ts.fData.fPsd.fDigis.size();
-
-  const std::vector<double> triggers = GetTriggerTimes(ts);
   LOG(debug) << "triggers: " << triggers.size();
 
   /// Create events
@@ -319,7 +222,7 @@ bool CbmDeviceEventBuilder::HandleData(FairMQParts& parts, int /*index*/)
   LOG(debug) << "vEvents size: " << vEvents.size();
 
   /// Send output message
-  if (!SendEvents(vEvents, tsMetaData, evtHeader)) { return false; }
+  if (!SendEvents(vEvents, tsMetaData)) { return false; }
 
   /// Write events to file
   // FIXME: poor man solution with lots of data copy until we undertand how to properly deal
@@ -329,8 +232,6 @@ bool CbmDeviceEventBuilder::HandleData(FairMQParts& parts, int /*index*/)
     (*fEventsSelOut) = std::move(vEvents);
     LOG(debug) << "fEventSel size: " << fEventsSelOut->size();
 
-    (*fCbmTsEventHeaderOut) = std::move(*evtHeader);
-
     new ((*fTimeSliceMetaDataArrayOut)[fTimeSliceMetaDataArrayOut->GetEntriesFast()])
       TimesliceMetaData(std::move(*tsMetaData));
 
@@ -343,71 +244,24 @@ bool CbmDeviceEventBuilder::HandleData(FairMQParts& parts, int /*index*/)
   return true;
 }
 
-void CbmDeviceEventBuilder::DumpTreeEntry()
+void CbmDevBuildEvents::DumpTreeEntry()
 {
   // Unpacked digis + CbmEvent output to root file
 
   /// FairRunOnline style
   fpFairRootMgr->StoreWriteoutBufferData(fpFairRootMgr->GetEventTime());
-  fpFairRootMgr->FillEventHeader(fCbmTsEventHeaderOut);
   fpFairRootMgr->Fill();
   fpFairRootMgr->DeleteOldWriteoutBufferData();
 }
 
-std::vector<double> CbmDeviceEventBuilder::GetTriggerTimes(const CbmDigiTimeslice& ts)
-{
-  std::vector<double> vDigiTimes;
-  switch (fTriggerDet) {
-    case ECbmModuleId::kMuch: {
-      vDigiTimes = GetDigiTimes(ts.fData.fMuch.fDigis);
-      break;
-    }
-    case ECbmModuleId::kSts: {
-      vDigiTimes = GetDigiTimes(ts.fData.fSts.fDigis);
-      break;
-    }
-    case ECbmModuleId::kTof: {
-      vDigiTimes = GetDigiTimes(ts.fData.fTof.fDigis);
-      break;
-    }
-    case ECbmModuleId::kTrd: {
-      vDigiTimes = GetDigiTimes(ts.fData.fTrd.fDigis);
-      break;
-    }
-    case ECbmModuleId::kRich: {
-      vDigiTimes = GetDigiTimes(ts.fData.fRich.fDigis);
-      break;
-    }
-    case ECbmModuleId::kPsd: {
-      vDigiTimes = GetDigiTimes(ts.fData.fPsd.fDigis);
-      break;
-    }
-    case ECbmModuleId::kT0: {
-      vDigiTimes = GetDigiTimes(ts.fData.fT0.fDigis);
-      break;
-    }
-    default: LOG(fatal) << "CbmDeviceEventBuilder::GetTriggerTimes(): Reading digis from unknown detector type!";
-  }
-  LOG(debug) << "CbmDeviceEventBuilder::GetTriggerTimes(): Building triggers from " << vDigiTimes.size() << " digis.";
-  return fTriggerAlgo(vDigiTimes, fTriggerWindow, fMinNumDigis, fDeadTime);
-}
-
-bool CbmDeviceEventBuilder::SendEvents(const std::vector<CbmDigiEvent>& vEvents, const TimesliceMetaData* tsMetaData,
-                                       const CbmTsEventHeader* eventHeader)
+bool CbmDevBuildEvents::SendEvents(const std::vector<CbmDigiEvent>& vEvents, const TimesliceMetaData* tsMetaData)
 {
   LOG(debug) << "Vector size: " << vEvents.size();
 
   FairMQParts partsOut;
 
-  /// Prepare serialized versions of the TS Event header
-  FairMQMessagePtr messTsHeader(NewMessage());
-  //  Serialize<RootSerializer>(*messTsHeader, eventHeader);
-  RootSerializer().Serialize(*messTsHeader, eventHeader);
-  partsOut.AddPart(std::move(messTsHeader));
-
   // Prepare TS meta data
   FairMQMessagePtr messTsMeta(NewMessage());
-  //  Serialize<RootSerializer>(*messTsMeta, tsMetaData);
   RootSerializer().Serialize(*messTsMeta, tsMetaData);
   partsOut.AddPart(std::move(messTsMeta));
 
@@ -430,7 +284,7 @@ bool CbmDeviceEventBuilder::SendEvents(const std::vector<CbmDigiEvent>& vEvents,
   return true;
 }
 
-void CbmDeviceEventBuilder::Finish()
+void CbmDevBuildEvents::Finish()
 {
   if ("" != fsOutputFileName) {
     // Clean closure of output to root file
@@ -440,12 +294,11 @@ void CbmDeviceEventBuilder::Finish()
   fbFinishDone = kTRUE;
 }
 
-CbmDeviceEventBuilder::~CbmDeviceEventBuilder()
+CbmDevBuildEvents::~CbmDevBuildEvents()
 {
   /// Close things properly if not alredy done
   if (!fbFinishDone) Finish();
   if (fEventsSelOut) { delete fEventsSelOut; }
   if (fpRun) { delete fpRun; }
-  if (fCbmTsEventHeaderOut) { delete fCbmTsEventHeaderOut; }
   if (fTimeSliceMetaDataArrayOut) { delete fTimeSliceMetaDataArrayOut; }
 }
diff --git a/reco/mq/CbmDevBuildEvents.h b/reco/mq/CbmDevBuildEvents.h
new file mode 100644
index 0000000000000000000000000000000000000000..ceb7c035529e3897914d8f8a2dd06d1e2e45ded2
--- /dev/null
+++ b/reco/mq/CbmDevBuildEvents.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Dominik Smith[committer] */
+
+/**
+ * CbmDevBuildEvents.h
+ *
+ * @since 2022-02-01
+ * @author D. Smith
+ */
+
+#ifndef CBMDEVICEEVENTBUILDER_H_
+#define CBMDEVICEEVENTBUILDER_H_
+
+/// CBM headers
+#include "EventBuilder.h"
+
+/// FAIRROOT headers
+#include "FairMQDevice.h"
+
+/// FAIRSOFT headers (geant, boost, ...)
+#include "Rtypes.h"
+#include "TObjArray.h"
+
+/// C/C++ headers
+#include <vector>
+
+class FairRunOnline;
+class FairRootManager;
+
+class TClonesArray;
+class TimesliceMetaData;
+
+class CbmDevBuildEvents : public FairMQDevice {
+public:
+  CbmDevBuildEvents();
+  virtual ~CbmDevBuildEvents();
+
+protected:
+  virtual void InitTask();
+  bool HandleData(FairMQParts&, int);
+
+private:
+  Bool_t fbFinishDone = false;  //! Keep track of whether the Finish was already called
+
+  /// User settings parameters
+  /// message queues
+  std::string fsChannelNameDataInput  = "trigger";
+  std::string fsChannelNameDataOutput = "events";
+
+  /// List of MQ channels names
+  std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
+
+  /// Statistics & first TS rejection
+  uint64_t fulNumMessages = 0;
+  uint64_t fulTsCounter   = 0;
+
+  /// Processing algos
+  cbm::algo::EventBuilder fEvbuildAlgo;
+
+  /// Data storage
+  std::string fsOutputFileName             = "";
+  FairRunOnline* fpRun                     = nullptr;
+  FairRootManager* fpFairRootMgr           = nullptr;
+  std::vector<CbmDigiEvent>* fEventsSelOut = nullptr;  // output container of CbmDigiEvents
+  TClonesArray* fTimeSliceMetaDataArrayOut = nullptr;  // output container of meta data
+
+  bool IsChannelNameAllowed(std::string channelName);
+  bool SendEvents(const std::vector<CbmDigiEvent>& vEvents, const TimesliceMetaData* tsMetaData);
+
+  // Get detector type from string containing name
+  ECbmModuleId GetDetectorId(std::string detName);
+
+  void DumpTreeEntry();
+  void Finish();
+};
+
+#endif /* CBMDEVICEEVENTBUILDER_H_ */
diff --git a/MQ/mcbm/CbmDeviceEventSink.cxx b/reco/mq/CbmDevEventSink.cxx
similarity index 85%
rename from MQ/mcbm/CbmDeviceEventSink.cxx
rename to reco/mq/CbmDevEventSink.cxx
index 1da07214f543a517f19f26cd96f3f7340e71202a..00b626742f754ee154c220d643a21f3f9e0575c1 100644
--- a/MQ/mcbm/CbmDeviceEventSink.cxx
+++ b/reco/mq/CbmDevEventSink.cxx
@@ -2,7 +2,7 @@
    SPDX-License-Identifier: GPL-3.0-only
    Authors: Pierre-Alain Loizeau [committer], Dominik Smith */
 
-#include "CbmDeviceEventSink.h"
+#include "CbmDevEventSink.h"
 
 /// CBM headers
 #include "CbmEvent.h"
@@ -48,12 +48,12 @@ using namespace std;
 
 //Bool_t bMcbm2018MonitorTaskT0ResetHistos = kFALSE;
 
-CbmDeviceEventSink::CbmDeviceEventSink() {}
+CbmDevEventSink::CbmDevEventSink() {}
 
-void CbmDeviceEventSink::InitTask()
+void CbmDevEventSink::InitTask()
 try {
   /// Read options from executable
-  LOG(info) << "Init options for CbmDeviceEventSink.";
+  LOG(info) << "Init options for CbmDevEventSink.";
 
   fsOutputFileName = fConfig->GetValue<std::string>("OutFileName");
 
@@ -67,10 +67,10 @@ try {
   fsChannelNameHistosInput = fConfig->GetValue<std::string>("ChNameIn");
 
   /// Associate the MissedTs Channel to the corresponding handler
-  OnData(fsChannelNameMissedTs, &CbmDeviceEventSink::HandleMissTsData);
+  OnData(fsChannelNameMissedTs, &CbmDevEventSink::HandleMissTsData);
 
   /// Associate the command Channel to the corresponding handler
-  OnData(fsChannelNameCommands, &CbmDeviceEventSink::HandleCommand);
+  OnData(fsChannelNameCommands, &CbmDevEventSink::HandleCommand);
 
   /// Associate the Event + Unp data Channel to the corresponding handler
   // Get the information about created channels from the device
@@ -88,7 +88,7 @@ try {
     LOG(info) << "Channel name: " << entry.first;
     if (std::string::npos != entry.first.find(fsChannelNameDataInput)) {
       if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
-      OnData(entry.first, &CbmDeviceEventSink::HandleData);
+      OnData(entry.first, &CbmDevEventSink::HandleData);
     }  // if( entry.first.find( "ts" )
   }    // for( auto const &entry : fChannels )
 
@@ -120,16 +120,11 @@ try {
   LOG(info) << "Init Root Output to " << fsOutputFileName;
 
   fpFairRootMgr->InitSink();
-  fEvtHeader = new CbmTsEventHeader();
-  fpFairRootMgr->Register("EventHeader.", "Event", fEvtHeader, kTRUE);
-
   /// Register all input data members with the FairRoot manager
   /// TS MetaData
   fpFairRootMgr->Register("TimesliceMetaData", "TS Meta Data", fTimeSliceMetaDataArray, kTRUE);
   /// CbmEvent
   fpFairRootMgr->RegisterAny("DigiEvent", fEventsSel, kTRUE);
-
-
   fpFairRootMgr->WriteFolder();
 
   LOG(info) << "Initialized outTree with rootMgr at " << fpFairRootMgr;
@@ -146,7 +141,7 @@ catch (InitTaskError& e) {
   cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
 }
 
-bool CbmDeviceEventSink::IsChannelNameAllowed(std::string channelName)
+bool CbmDevEventSink::IsChannelNameAllowed(std::string channelName)
 {
   for (auto const& entry : fsAllowedChannels) {
     std::size_t pos1 = channelName.find(entry);
@@ -164,7 +159,7 @@ bool CbmDeviceEventSink::IsChannelNameAllowed(std::string channelName)
   return false;
 }
 
-bool CbmDeviceEventSink::InitHistograms()
+bool CbmDevEventSink::InitHistograms()
 {
   /// Histos creation and obtain pointer on them
   /// Trigger histo creation, filling vHistos and vCanvases
@@ -214,7 +209,7 @@ bool CbmDeviceEventSink::InitHistograms()
 
 //--------------------------------------------------------------------//
 // handler is called whenever a message arrives on fsChannelNameMissedTs, with a reference to the message and a sub-channel index (here 0)
-bool CbmDeviceEventSink::HandleMissTsData(FairMQMessagePtr& msg, int /*index*/)
+bool CbmDevEventSink::HandleMissTsData(FairMQMessagePtr& msg, int /*index*/)
 {
   std::vector<uint64_t> vIndices;
   std::string msgStrMissTs(static_cast<char*>(msg->GetData()), msg->GetSize());
@@ -231,7 +226,7 @@ bool CbmDeviceEventSink::HandleMissTsData(FairMQMessagePtr& msg, int /*index*/)
 }
 //--------------------------------------------------------------------//
 // handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
-bool CbmDeviceEventSink::HandleData(FairMQParts& parts, int /*index*/)
+bool CbmDevEventSink::HandleData(FairMQParts& parts, int /*index*/)
 {
   fulNumMessages++;
   LOG(debug) << "Received message number " << fulNumMessages << " with " << parts.Size() << " parts"
@@ -300,7 +295,7 @@ bool CbmDeviceEventSink::HandleData(FairMQParts& parts, int /*index*/)
   return true;
 }
 //--------------------------------------------------------------------//
-bool CbmDeviceEventSink::HandleCommand(FairMQMessagePtr& msg, int /*index*/)
+bool CbmDevEventSink::HandleCommand(FairMQMessagePtr& msg, int /*index*/)
 {
   /*
    std::string sCommand( static_cast< char * >( msg->GetData() ),
@@ -323,7 +318,7 @@ bool CbmDeviceEventSink::HandleCommand(FairMQMessagePtr& msg, int /*index*/)
 
     /// Extract the last TS index and global full TS count
     if (std::string::npos == charPosDel) {
-      LOG(fatal) << "CbmDeviceEventSink::HandleCommand => "
+      LOG(fatal) << "CbmDevEventSink::HandleCommand => "
                  << "Incomplete EOF command received: " << sCommand;
       return false;
     }  // if( std::string::npos == charPosDel )
@@ -333,7 +328,7 @@ bool CbmDeviceEventSink::HandleCommand(FairMQMessagePtr& msg, int /*index*/)
     charPosDel        = sNext.find(' ');
 
     if (std::string::npos == charPosDel) {
-      LOG(fatal) << "CbmDeviceEventSink::HandleCommand => "
+      LOG(fatal) << "CbmDevEventSink::HandleCommand => "
                  << "Incomplete EOF command received: " << sCommand;
       return false;
     }  // if( std::string::npos == charPosDel )
@@ -342,11 +337,11 @@ bool CbmDeviceEventSink::HandleCommand(FairMQMessagePtr& msg, int /*index*/)
     charPosDel++;
     fuTotalTsCount = std::stoul(sNext.substr(charPosDel));
 
-    LOG(info) << "CbmDeviceEventSink::HandleCommand => "
+    LOG(info) << "CbmDevEventSink::HandleCommand => "
               << "Received EOF command with final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
     /// End of data: clean save of data + close file + send last state of histos if enabled
     if (fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount) {
-      LOG(info) << "CbmDeviceEventSink::HandleCommand => "
+      LOG(info) << "CbmDevEventSink::HandleCommand => "
                 << "Found final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
       Finish();
     }  // if( fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount )
@@ -363,7 +358,7 @@ bool CbmDeviceEventSink::HandleCommand(FairMQMessagePtr& msg, int /*index*/)
   return true;
 }
 //--------------------------------------------------------------------//
-void CbmDeviceEventSink::CheckTsQueues()
+void CbmDevEventSink::CheckTsQueues()
 {
   bool bHoleFoundInBothQueues = false;
 
@@ -387,8 +382,7 @@ void CbmDeviceEventSink::CheckTsQueues()
       continue;
     }  // if( fmFullTsStorage.end() != itFullTs && fuPrevTsIndex + 1 == (*itFullTs).first() )
     if (fmFullTsStorage.end() != itFullTs)
-      LOG(debug) << "CbmDeviceEventSink::CheckTsQueues => Full TS " << (*itFullTs).first << " VS "
-                 << (fuPrevTsIndex + 1);
+      LOG(debug) << "CbmDevEventSink::CheckTsQueues => Full TS " << (*itFullTs).first << " VS " << (fuPrevTsIndex + 1);
     /// Check if the first TS in the missed TS queue is the next one
     if (fvulMissedTsIndices.end() != itMissTs
         && ((0 == fuPrevTsIndex && fuPrevTsIndex == (*itMissTs))
@@ -410,16 +404,16 @@ void CbmDeviceEventSink::CheckTsQueues()
       continue;
     }  // if( fvulMissedTsIndices.end() != itMissTs && fuPrevTsIndex + 1 == (*itMissTs ) )
     if (fvulMissedTsIndices.end() != itMissTs)
-      LOG(debug) << "CbmDeviceEventSink::CheckTsQueues => Empty TS " << (*itMissTs) << " VS " << (fuPrevTsIndex + 1);
+      LOG(debug) << "CbmDevEventSink::CheckTsQueues => Empty TS " << (*itMissTs) << " VS " << (fuPrevTsIndex + 1);
 
     /// Should be reached only if both queues at the end or hole found in both
     bHoleFoundInBothQueues = true;
   }  // while( !bHoleFoundInBothQueues )
 
-  LOG(debug) << "CbmDeviceEventSink::CheckTsQueues => buffered TS " << fmFullTsStorage.size() << " buffered empties "
+  LOG(debug) << "CbmDevEventSink::CheckTsQueues => buffered TS " << fmFullTsStorage.size() << " buffered empties "
              << fvulMissedTsIndices.size();
   for (auto it = fmFullTsStorage.begin(); it != fmFullTsStorage.end(); ++it) {
-    LOG(debug) << "CbmDeviceEventSink::CheckTsQueues => buffered TS index " << (*it).first;
+    LOG(debug) << "CbmDevEventSink::CheckTsQueues => buffered TS index " << (*it).first;
   }
 
   /// Delete the processed entries
@@ -428,19 +422,17 @@ void CbmDeviceEventSink::CheckTsQueues()
 
   /// End of data: clean save of data + close file + send last state of histos if enabled
   if (fbReceivedEof && fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount) {
-    LOG(info) << "CbmDeviceEventSink::CheckTsQueues => "
+    LOG(info) << "CbmDevEventSink::CheckTsQueues => "
               << "Found final TS index " << fuLastTsIndex << " and total nb TS " << fuTotalTsCount;
     Finish();
   }  // if( fbReceivedEof && fuPrevTsIndex == fuLastTsIndex && fulTsCounter == fuTotalTsCount )
 }
 //--------------------------------------------------------------------//
-void CbmDeviceEventSink::PrepareTreeEntry(CbmEventTimeslice unpTs)
+void CbmDevEventSink::PrepareTreeEntry(CbmEventTimeslice unpTs)
 {
   /// FIXME: poor man solution with lots of data copy until we undertsnad how to properly deal
   /// with FairMq messages ownership and memory managment
 
-  (*fEvtHeader) = std::move(unpTs.fCbmTsEventHeader);
-
   /// FIXME: Not sure if this is the proper way to insert the data
   new ((*fTimeSliceMetaDataArray)[fTimeSliceMetaDataArray->GetEntriesFast()])
     TimesliceMetaData(std::move(unpTs.fTsMetaData));
@@ -449,25 +441,13 @@ void CbmDeviceEventSink::PrepareTreeEntry(CbmEventTimeslice unpTs)
   (*fEventsSel) = std::move(unpTs.GetSelectedData());
 }
 
-void CbmDeviceEventSink::DumpTreeEntry()
+void CbmDevEventSink::DumpTreeEntry()
 {
   // Unpacked digis + CbmEvent output to root file
-  /*
- * NH style
-//      fpFairRootMgr->FillEventHeader(fEvtHeader);
-//      LOG(info) << "Fill WriteOutBuffer with FairRootManager at " << fpFairRootMgr;
-//      fpOutRootFile->cd();
-      fpFairRootMgr->Fill();
-      fpFairRootMgr->StoreWriteoutBufferData( fpFairRootMgr->GetEventTime() );
-      //fpFairRootMgr->StoreAllWriteoutBufferData();
-      fpFairRootMgr->DeleteOldWriteoutBufferData();
-*/
   /// FairRunOnline style
   fpFairRootMgr->StoreWriteoutBufferData(fpFairRootMgr->GetEventTime());
-  fpFairRootMgr->FillEventHeader(fEvtHeader);
   fpFairRootMgr->Fill();
   fpFairRootMgr->DeleteOldWriteoutBufferData();
-  //  fpFairRootMgr->Write();
 
   /// Clear metadata array
   fTimeSliceMetaDataArray->Clear();
@@ -478,12 +458,11 @@ void CbmDeviceEventSink::DumpTreeEntry()
 
 //--------------------------------------------------------------------//
 
-bool CbmDeviceEventSink::SendHistoConfAndData()
+bool CbmDevEventSink::SendHistoConfAndData()
 {
   /// Prepare multiparts message and header
   std::pair<uint32_t, uint32_t> pairHeader(fvpsHistosFolder.size(), fvpsCanvasConfig.size());
   FairMQMessagePtr messageHeader(NewMessage());
-  //  Serialize<BoostSerializer<std::pair<uint32_t, uint32_t>>>(*messageHeader, pairHeader);
   BoostSerializer<std::pair<uint32_t, uint32_t>>().Serialize(*messageHeader, pairHeader);
 
   FairMQParts partsOut;
@@ -492,38 +471,21 @@ bool CbmDeviceEventSink::SendHistoConfAndData()
   for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto) {
     /// Serialize the vector of histo config into a single MQ message
     FairMQMessagePtr messageHist(NewMessage());
-    //    Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageHist, fvpsHistosFolder[uHisto]);
     BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageHist, fvpsHistosFolder[uHisto]);
 
     partsOut.AddPart(std::move(messageHist));
   }  // for (UInt_t uHisto = 0; uHisto < fvpsHistosFolder.size(); ++uHisto)
 
-  /// Catch case where no histos are registered!
-  /// => Add empty message
-  if (0 == fvpsHistosFolder.size()) {
-    FairMQMessagePtr messageHist(NewMessage());
-    partsOut.AddPart(std::move(messageHist));
-  }
-
   for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv) {
     /// Serialize the vector of canvas config into a single MQ message
     FairMQMessagePtr messageCan(NewMessage());
-    //    Serialize<BoostSerializer<std::pair<std::string, std::string>>>(*messageCan, fvpsCanvasConfig[uCanv]);
     BoostSerializer<std::pair<std::string, std::string>>().Serialize(*messageCan, fvpsCanvasConfig[uCanv]);
 
     partsOut.AddPart(std::move(messageCan));
   }  // for (UInt_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv)
 
-  /// Catch case where no Canvases are registered!
-  /// => Add empty message
-  if (0 == fvpsCanvasConfig.size()) {
-    FairMQMessagePtr messageHist(NewMessage());
-    partsOut.AddPart(std::move(messageHist));
-  }
-
   /// Serialize the array of histos into a single MQ message
   FairMQMessagePtr msgHistos(NewMessage());
-  //  Serialize<RootSerializer>(*msgHistos, &fArrayHisto);
   RootSerializer().Serialize(*msgHistos, &fArrayHisto);
 
   partsOut.AddPart(std::move(msgHistos));
@@ -540,11 +502,10 @@ bool CbmDeviceEventSink::SendHistoConfAndData()
   return true;
 }
 
-bool CbmDeviceEventSink::SendHistograms()
+bool CbmDevEventSink::SendHistograms()
 {
   /// Serialize the array of histos into a single MQ message
   FairMQMessagePtr message(NewMessage());
-  //  Serialize<RootSerializer>(*message, &fArrayHisto);
   RootSerializer().Serialize(*message, &fArrayHisto);
 
   /// Send message to the common histogram messages queue
@@ -560,7 +521,7 @@ bool CbmDeviceEventSink::SendHistograms()
 }
 
 //--------------------------------------------------------------------//
-CbmDeviceEventSink::~CbmDeviceEventSink()
+CbmDevEventSink::~CbmDevEventSink()
 {
   /// FIXME: Add pointers check before delete
 
@@ -574,7 +535,7 @@ CbmDeviceEventSink::~CbmDeviceEventSink()
   delete fpRun;
 }
 
-void CbmDeviceEventSink::Finish()
+void CbmDevEventSink::Finish()
 {
   // Clean closure of output to root file
   fpFairRootMgr->Write();
@@ -602,21 +563,8 @@ CbmEventTimeslice::CbmEventTimeslice(FairMQParts& parts)
   /// Extract unpacked data from input message
   uint32_t uPartIdx = 0;
 
-  /// TODO: code order of vectors in the TS header!!
-
-  /// TS header
-  TObject* tempObjectPointer = nullptr;
-  RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectPointer);
-  if (tempObjectPointer && TString(tempObjectPointer->ClassName()).EqualTo("CbmTsEventHeader")) {
-    fCbmTsEventHeader = *(static_cast<CbmTsEventHeader*>(tempObjectPointer));
-  }
-  else {
-    LOG(fatal) << "Failed to deserialize the TS header";
-  }
-  ++uPartIdx;
-
   /// TS metadata
-  tempObjectPointer = nullptr;
+  TObject* tempObjectPointer = nullptr;
   RootSerializer().Deserialize(*parts.At(uPartIdx), tempObjectPointer);
 
   if (tempObjectPointer && TString(tempObjectPointer->ClassName()).EqualTo("TimesliceMetaData")) {
diff --git a/MQ/mcbm/CbmDeviceEventSink.h b/reco/mq/CbmDevEventSink.h
similarity index 90%
rename from MQ/mcbm/CbmDeviceEventSink.h
rename to reco/mq/CbmDevEventSink.h
index 9c10bf426bedab4f826c9c1dde3c2d53e8ecb31b..b05592bb3796d7ade0d5c590c63a6d6d83c64fee 100644
--- a/MQ/mcbm/CbmDeviceEventSink.h
+++ b/reco/mq/CbmDevEventSink.h
@@ -15,7 +15,6 @@
 #include "CbmStsDigi.h"
 #include "CbmTofDigi.h"
 #include "CbmTrdDigi.h"
-#include "CbmTsEventHeader.h"
 
 #include "TimesliceMetaData.h"
 
@@ -35,7 +34,6 @@
 class TFile;
 class TList;
 class TClonesArray;
-//class TimesliceMetaData;
 class FairRunOnline;
 class FairRootManager;
 
@@ -47,16 +45,14 @@ public:
 
   std::vector<CbmDigiEvent> GetSelectedData();
 
-  /// TS information in header
-  CbmTsEventHeader fCbmTsEventHeader;
   TimesliceMetaData fTsMetaData;
   std::vector<CbmDigiEvent> fvEvents;
 };
 
-class CbmDeviceEventSink : public FairMQDevice {
+class CbmDevEventSink : public FairMQDevice {
 public:
-  CbmDeviceEventSink();
-  virtual ~CbmDeviceEventSink();
+  CbmDevEventSink();
+  virtual ~CbmDevEventSink();
 
 protected:
   virtual void InitTask();
@@ -87,10 +83,6 @@ private:
   /// List of MQ channels names
   std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
 
-  /// Parameters management
-  //      TList* fParCList = nullptr;
-  //      Bool_t InitParameters( TList* fParCList );
-
   /// Statistics & missed TS detection
   uint64_t fuPrevTsIndex                                 = 0;
   uint64_t fulNumMessages                                = 0;
@@ -104,8 +96,6 @@ private:
   uint64_t fuTotalTsCount = 0;
 
   /// Data reception
-  /// Event (TS) header
-  CbmTsEventHeader* fEvtHeader = nullptr;
   /// TS MetaData storage
   TClonesArray* fTimeSliceMetaDataArray = nullptr;  //!
   TimesliceMetaData* fTsMetaData        = nullptr;
diff --git a/reco/mq/CbmDevTrigger.cxx b/reco/mq/CbmDevTrigger.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..29222c3475663cc279673f251d5fb1db7ac3f3e0
--- /dev/null
+++ b/reco/mq/CbmDevTrigger.cxx
@@ -0,0 +1,179 @@
+/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau[committer], Dominik Smith */
+
+#include "CbmDevTrigger.h"
+
+/// CBM headers
+#include "CbmDigiTimeslice.h"
+#include "CbmMQDefs.h"
+
+/// FAIRROOT headers
+#include "FairMQLogger.h"
+#include "FairMQProgOptions.h"
+
+#include "BoostSerializer.h"
+
+#include "RootSerializer.h"
+
+/// FAIRSOFT headers (geant, boost, ...)
+#include "TimesliceMetaData.h"
+
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/serialization/utility.hpp>
+
+/// C/C++ headers
+#include <array>
+#include <iomanip>
+#include <stdexcept>
+#include <string>
+struct InitTaskError : std::runtime_error {
+  using std::runtime_error::runtime_error;
+};
+
+using namespace std;
+
+CbmDevTrigger::CbmDevTrigger() {}
+
+void CbmDevTrigger::InitTask()
+try {
+  /// Read options from executable
+  LOG(info) << "Init options for CbmDevTrigger.";
+
+  // Trigger algorithm params
+  const std::string sTriggerDet = fConfig->GetValue<std::string>("TriggerDet");
+  fTriggerWindow                = fConfig->GetValue<double>("TriggerWin");
+  fMinNumDigis                  = fConfig->GetValue<int32_t>("TriggerMinDigis");
+  fDeadTime                     = fConfig->GetValue<double>("TriggerDeadTime");
+
+  fChannelNameDataInput  = fConfig->GetValue<std::string>("TsNameIn");
+  fChannelNameDataOutput = fConfig->GetValue<std::string>("TriggerNameOut");
+
+  OnData(fChannelNameDataInput, &CbmDevTrigger::HandleData);
+
+  /// Extract refdet
+  fTriggerDet = GetDetectorId(sTriggerDet);
+
+  if (ECbmModuleId::kNotExist == fTriggerDet) { throw InitTaskError("CbmDevTrigger: Trigger detector not set."); }
+}
+catch (InitTaskError& e) {
+  LOG(error) << e.what();
+  // Wrapper defined in CbmMQDefs.h to support different FairMQ versions
+  cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
+}
+
+ECbmModuleId CbmDevTrigger::GetDetectorId(std::string detName)
+{
+  /// FIXME: Disable clang formatting for now as it corrupts all alignment
+  /* clang-format off */
+  ECbmModuleId detId = ("T0"   == detName ? ECbmModuleId::kT0
+                       : ("Sts"  == detName ? ECbmModuleId::kSts
+                       : ("Much" == detName ? ECbmModuleId::kMuch
+                       : ("Trd"  == detName ? ECbmModuleId::kTrd
+                       : ("Tof"  == detName ? ECbmModuleId::kTof
+                       : ("Rich" == detName ? ECbmModuleId::kRich
+                       : ("Psd"  == detName ? ECbmModuleId::kPsd
+                                             : ECbmModuleId::kNotExist)))))));
+  return detId; 
+  /// FIXME: Re-enable clang formatting after formatted lines
+  /* clang-format on */
+}
+
+// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
+bool CbmDevTrigger::HandleData(FairMQParts& parts, int /*index*/)
+{
+  fNumMessages++;
+  LOG(info) << "Received message number " << fNumMessages << " with " << parts.Size() << " parts"
+            << ", size0: " << parts.At(0)->GetSize();
+
+  if (0 == fNumMessages % 10000) LOG(info) << "Received " << fNumMessages << " messages";
+
+  /// Extract unpacked data from input message
+  CbmDigiTimeslice ts;
+
+  std::string msgStrTS(static_cast<char*>(parts.At(0)->GetData()), (parts.At(0))->GetSize());
+  std::istringstream issTS(msgStrTS);
+  boost::archive::binary_iarchive inputArchiveTS(issTS);
+  inputArchiveTS >> ts;
+
+  LOG(debug) << "T0 Vector size: " << ts.fData.fT0.fDigis.size();
+  LOG(debug) << "STS Vector size: " << ts.fData.fSts.fDigis.size();
+  LOG(debug) << "MUCH Vector size: " << ts.fData.fMuch.fDigis.size();
+  LOG(debug) << "TRD Vector size: " << ts.fData.fTrd.fDigis.size();
+  LOG(debug) << "TOF Vector size: " << ts.fData.fTof.fDigis.size();
+  LOG(debug) << "RICH Vector size: " << ts.fData.fRich.fDigis.size();
+  LOG(debug) << "PSD Vector size: " << ts.fData.fPsd.fDigis.size();
+
+  const std::vector<double> triggers = GetTriggerTimes(ts);
+  LOG(debug) << "triggers: " << triggers.size();
+
+  /// Send output message
+  if (!SendTriggers(triggers, parts)) { return false; }
+
+  return true;
+}
+
+std::vector<double> CbmDevTrigger::GetTriggerTimes(const CbmDigiTimeslice& ts)
+{
+  std::vector<double> vDigiTimes;
+  switch (fTriggerDet) {
+    case ECbmModuleId::kMuch: {
+      vDigiTimes = GetDigiTimes(ts.fData.fMuch.fDigis);
+      break;
+    }
+    case ECbmModuleId::kSts: {
+      vDigiTimes = GetDigiTimes(ts.fData.fSts.fDigis);
+      break;
+    }
+    case ECbmModuleId::kTof: {
+      vDigiTimes = GetDigiTimes(ts.fData.fTof.fDigis);
+      break;
+    }
+    case ECbmModuleId::kTrd: {
+      vDigiTimes = GetDigiTimes(ts.fData.fTrd.fDigis);
+      break;
+    }
+    case ECbmModuleId::kRich: {
+      vDigiTimes = GetDigiTimes(ts.fData.fRich.fDigis);
+      break;
+    }
+    case ECbmModuleId::kPsd: {
+      vDigiTimes = GetDigiTimes(ts.fData.fPsd.fDigis);
+      break;
+    }
+    case ECbmModuleId::kT0: {
+      vDigiTimes = GetDigiTimes(ts.fData.fT0.fDigis);
+      break;
+    }
+    default: LOG(fatal) << "CbmDevTrigger::GetTriggerTimes(): Reading digis from unknown detector type!";
+  }
+  LOG(debug) << "CbmDevTrigger::GetTriggerTimes(): Building triggers from " << vDigiTimes.size() << " digis.";
+  return fTriggerAlgo(vDigiTimes, fTriggerWindow, fMinNumDigis, fDeadTime);
+}
+
+bool CbmDevTrigger::SendTriggers(const std::vector<double>& vTriggers, FairMQParts& partsIn)
+{
+  LOG(debug) << "Vector size: " << vTriggers.size();
+
+  FairMQParts partsOut;
+  partsOut.AddPart(std::move(partsIn.At(0)));  // DigiTimeslice
+  partsOut.AddPart(std::move(partsIn.At(1)));  // TsMetaData
+
+  // Prepare trigger vector.
+  std::stringstream ossTrig;
+  boost::archive::binary_oarchive oaTrig(ossTrig);
+  oaTrig << vTriggers;
+  std::string* strMsgTrig = new std::string(ossTrig.str());
+
+  partsOut.AddPart(NewMessage(
+    const_cast<char*>(strMsgTrig->c_str()),  // data
+    strMsgTrig->length(),                    // size
+    [](void*, void* object) { delete static_cast<std::string*>(object); },
+    strMsgTrig));  // object that manages the data
+
+  if (Send(partsOut, fChannelNameDataOutput) < 0) {
+    LOG(error) << "Problem sending data to " << fChannelNameDataOutput;
+    return false;
+  }
+  return true;
+}
diff --git a/reco/mq/CbmDevTrigger.h b/reco/mq/CbmDevTrigger.h
new file mode 100644
index 0000000000000000000000000000000000000000..5ab19fdf16ded615eb797db1462477a019725c5a
--- /dev/null
+++ b/reco/mq/CbmDevTrigger.h
@@ -0,0 +1,82 @@
+/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Dominik Smith[committer] */
+
+/**
+ * CbmDevTrigger.h
+ *
+ * @since 2022-02-01
+ * @author D. Smith
+ */
+
+#ifndef CBMDEVICETRIGGER_H_
+#define CBMDEVICETRIGGER_H_
+
+/// CBM headers
+#include "CbmDefs.h"
+
+#include "TimeClusterTrigger.h"
+
+/// FAIRROOT headers
+#include "FairMQDevice.h"
+
+/// FAIRSOFT headers (geant, boost, ...)
+#include "Rtypes.h"
+#include "TObjArray.h"
+
+/// C/C++ headers
+#include <chrono>
+#include <vector>
+
+class CbmDigiTimeslice;
+class CbmTsEventHeader;
+class TimesliceMetaData;
+
+class CbmDevTrigger : public FairMQDevice {
+public:
+  CbmDevTrigger();
+  virtual ~CbmDevTrigger() {};
+
+protected:
+  virtual void InitTask();
+  bool HandleData(FairMQParts&, int);
+
+private:
+  /// User settings parameters
+  /// Algo enum settings
+  ECbmModuleId fTriggerDet = ECbmModuleId::kNotExist;
+
+  /// message queues
+  std::string fChannelNameDataInput  = "";
+  std::string fChannelNameDataOutput = "";
+
+  /// Statistics
+  uint64_t fNumMessages = 0;
+
+  /// Processing algos
+  cbm::algo::TimeClusterTrigger fTriggerAlgo;
+
+  // Trigger algorithm params
+  double fTriggerWindow = 0.;
+  int32_t fMinNumDigis  = 0;
+  double fDeadTime      = 0.;
+
+  bool SendTriggers(const std::vector<double>& vTriggers, FairMQParts& partsIn);
+
+  // --- Extract digi times into to a vector
+  template<class TDigi>
+  std::vector<double> GetDigiTimes(const std::vector<TDigi>& digiVec)
+  {
+    std::vector<double> digiTimes(digiVec.size());
+    std::transform(digiVec.begin(), digiVec.end(), digiTimes.begin(), [](const TDigi& digi) { return digi.GetTime(); });
+    return digiTimes;
+  }
+
+  // Get trigger times using trigger algorithm
+  std::vector<double> GetTriggerTimes(const CbmDigiTimeslice& ts);
+
+  // Get detector type from string containing name
+  ECbmModuleId GetDetectorId(std::string detName);
+};
+
+#endif /* CBMDEVICETRIGGER_H_ */
diff --git a/reco/mq/CbmDevUnpack.cxx b/reco/mq/CbmDevUnpack.cxx
index 6f08b19f7dda4fb94d135952d45c3d61709f9e54..a3bb6edfe284467546983985bfd98fc65d5eaafc 100644
--- a/reco/mq/CbmDevUnpack.cxx
+++ b/reco/mq/CbmDevUnpack.cxx
@@ -59,9 +59,6 @@ catch (InitTaskError& e) {
 
 Bool_t CbmDevUnpack::InitAlgos()
 {
-  /// Event header object
-  fCbmTsEventHeader = new CbmTsEventHeader();
-
   // --- Common parameters for all components
   uint32_t numChansPerAsic   = 128;  // R/O channels per ASIC
   uint32_t numAsicsPerModule = 16;   // Number of ASICs per module
@@ -158,9 +155,6 @@ bool CbmDevUnpack::ConditionalRun()
   if (!SendData(digiTs, TsMetaData)) return false;
   LOG(debug) << "Unpack: Sent TS index " << ts.index();
 
-  // Reset the event header for a new timeslice
-  fCbmTsEventHeader->Reset();
-
   return true;
 }
 
@@ -168,11 +162,6 @@ bool CbmDevUnpack::SendData(const CbmDigiTimeslice& timeslice, const TimesliceMe
 {
   FairMQParts parts;
 
-  /// Prepare serialized versions of the TS Event header
-  FairMQMessagePtr messTsHeader(NewMessage());
-  RootSerializer().Serialize(*messTsHeader, fCbmTsEventHeader);
-  parts.AddPart(std::move(messTsHeader));
-
   /// Prepare serialized version of Digi Timeslice
   std::stringstream ossTS;
   boost::archive::binary_oarchive oaTS(ossTS);
@@ -201,18 +190,10 @@ bool CbmDevUnpack::SendData(const CbmDigiTimeslice& timeslice, const TimesliceMe
   return true;
 }
 
-CbmDevUnpack::~CbmDevUnpack()
-{
-  if (fCbmTsEventHeader) { delete fCbmTsEventHeader; }
-}
-
 CbmDigiTimeslice CbmDevUnpack::DoUnpack(const fles::Timeslice& timeslice)
 {
   fNumTs++;
 
-  fCbmTsEventHeader->SetTsIndex(timeslice.index());
-  fCbmTsEventHeader->SetTsStartTime(timeslice.start_time());
-
   // Output digi timeslice
   CbmDigiTimeslice digiTs;
 
@@ -281,9 +262,6 @@ CbmDigiTimeslice CbmDevUnpack::DoUnpack(const fles::Timeslice& timeslice)
 
   }  //# component
 
-  // --- Add Sts Digis to header
-  fCbmTsEventHeader->AddNDigisSts(numDigis);
-
   // --- Sorting of output digis. Is required by both digi trigger and event builder.
   std::sort(digiTs.fData.fSts.fDigis.begin(), digiTs.fData.fSts.fDigis.end(),
             [](CbmStsDigi digi1, CbmStsDigi digi2) { return digi1.GetTime() < digi2.GetTime(); });
diff --git a/reco/mq/CbmDevUnpack.h b/reco/mq/CbmDevUnpack.h
index ef273d4bdf2f0c0eae5f5ee2d5246358d19a86d9..03bde82adb2e785322fe0b5f0cb8039acd3602a1 100644
--- a/reco/mq/CbmDevUnpack.h
+++ b/reco/mq/CbmDevUnpack.h
@@ -13,7 +13,6 @@
 #define CBMDEVUNPACK_H
 
 #include "CbmMqTMessage.h"
-#include "CbmTsEventHeader.h"
 
 #include "Timeslice.hpp"
 
@@ -36,7 +35,7 @@ struct CbmDigiTimeslice;
 class CbmDevUnpack : public FairMQDevice {
 public:
   CbmDevUnpack();
-  virtual ~CbmDevUnpack();
+  virtual ~CbmDevUnpack() {};
 
 private:
   std::map<uint16_t, cbm::algo::UnpackSts> fAlgoSts = {};
@@ -51,9 +50,6 @@ private:
   size_t fNumMessages = 0;
   size_t fNumTs       = 0;
 
-  /// Pointer to the Timeslice header conatining start time and index
-  CbmTsEventHeader* fCbmTsEventHeader = nullptr;
-
   /** @brief Read command line parameters for MQ device */
   virtual void InitTask();
 
diff --git a/reco/mq/runBuildEvents.cxx b/reco/mq/runBuildEvents.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fac1edb137c86ead3da245a6362058b2a87e1280
--- /dev/null
+++ b/reco/mq/runBuildEvents.cxx
@@ -0,0 +1,28 @@
+/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Dominik Smith [committer] */
+
+#include "CbmDevBuildEvents.h"
+
+#include <iomanip>
+#include <string>
+
+#include "runFairMQDevice.h"
+
+namespace bpo = boost::program_options;
+using namespace std;
+
+void addCustomOptions(bpo::options_description& options)
+{
+  options.add_options()("OutFileName", bpo::value<std::string>()->default_value(""),
+                        "Name (full or relative path) of the output .root file ");
+  options.add_options()("SetEvbuildWin", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
+                        "Set event builder window for selected detector, use string matching "
+                        "ECbmModuleId,dWinBeg,dWinEnd e.g. kSts,-10.5,100.0");
+  options.add_options()("TrigNameIn", bpo::value<std::string>()->default_value("trigger"),
+                        "MQ channel name for TS data and triggers");
+  options.add_options()("EvtNameOut", bpo::value<std::string>()->default_value("events"),
+                        "MQ channel name for built events");
+}
+
+FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDevBuildEvents(); }
diff --git a/MQ/mcbm/runEventSink.cxx b/reco/mq/runEventSink.cxx
similarity index 96%
rename from MQ/mcbm/runEventSink.cxx
rename to reco/mq/runEventSink.cxx
index 9c014129140b86e5c72d64fc13b51356404686a1..ec49760825a2a5e85bf328979ce2ec95edeb527a 100644
--- a/MQ/mcbm/runEventSink.cxx
+++ b/reco/mq/runEventSink.cxx
@@ -2,7 +2,7 @@
    SPDX-License-Identifier: GPL-3.0-only
    Authors: Pierre-Alain Loizeau [committer] */
 
-#include "CbmDeviceEventSink.h"
+#include "CbmDevEventSink.h"
 
 #include <iomanip>
 #include <string>
@@ -32,4 +32,4 @@ void addCustomOptions(bpo::options_description& options)
                         "MQ channel name for histos");
 }
 
-FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDeviceEventSink(); }
+FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDevEventSink(); }
diff --git a/reco/mq/runTrigger.cxx b/reco/mq/runTrigger.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e030e2a64109edd5cb21cd320037f57aa58752bc
--- /dev/null
+++ b/reco/mq/runTrigger.cxx
@@ -0,0 +1,29 @@
+/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Dominik Smith [committer] */
+
+#include "CbmDevTrigger.h"
+
+#include <iomanip>
+#include <string>
+
+#include "runFairMQDevice.h"
+
+namespace bpo = boost::program_options;
+using namespace std;
+
+void addCustomOptions(bpo::options_description& options)
+{
+  options.add_options()("TriggerWin", bpo::value<double>()->default_value(0.0), "Time window for trigger algorithm");
+  options.add_options()("TriggerMinDigis", bpo::value<int32_t>()->default_value(1),
+                        "Minimum digi count for trigger algorithm");
+  options.add_options()("TriggerDeadTime", bpo::value<double>()->default_value(0.0), "Dead time for trigger algorithm");
+  options.add_options()("TriggerDet", bpo::value<std::string>()->default_value(""),
+                        "Set the trigger detector, use string matching an ECbmModuleId ");
+  options.add_options()("TsNameIn", bpo::value<std::string>()->default_value("unpts_0"),
+                        "MQ channel name for unpacked TS data");
+  options.add_options()("TriggerNameOut", bpo::value<std::string>()->default_value("trigger"),
+                        "MQ channel name for trigger times");
+}
+
+FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDevTrigger(); }
diff --git a/reco/mq/startUnpack.sh.in b/reco/mq/startUnpack.sh.in
index 37b772b9d971854bcdc1f569531fc108bd976b27..1e598a20d0d6ad4a03fffc36a53e9e93a77a0ed2 100755
--- a/reco/mq/startUnpack.sh.in
+++ b/reco/mq/startUnpack.sh.in
@@ -38,14 +38,14 @@ if [ $# -ge 1 ]; then
     echo 'Starting connection to local stream'
     echo ' for other usages, please supply at least a filename.'
     echo 'Possible usages are:'
-    echo 'startMQMcbmPulserMonitor2020.sh'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <full filename pattern list>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <filename pattern> <folder_path>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s>'
-    echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s> <Max Hist pub. in s>'
+    echo 'startUnpack.sh'
+    echo 'startUnpack.sh <Nb Unp & Moni processes>'
+    echo 'startUnpack.sh <Nb Unp & Moni processes> <full filename pattern list>'
+    echo 'startUnpack.sh <Nb Unp & Moni processes> <filename pattern> <folder_path>'
+    echo 'startUnpack.sh <Nb Unp & Moni processes> "" "" <hostname(s) list>'
+    echo 'startUnpack.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS>'
+    echo 'startUnpack.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s>'
+    echo 'startUnpack.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s> <Max Hist pub. in s>'
     _filename=""
     _dirname=""
     _hostname="localhost"
@@ -54,14 +54,14 @@ else
   echo 'Starting connection to local stream with 1 monitor process'
   echo ' for other usages, please supply at least a filename.'
   echo 'Possible usages are:'
-  echo 'startMQMcbmPulserMonitor2020.sh'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <full filename pattern list>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> <filename pattern> <folder_path>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s>'
-  echo 'startMQMcbmPulserMonitor2020.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s> <Max Hist pub. in s>'
+  echo 'startUnpack.sh'
+  echo 'startUnpack.sh <Nb Unp & Moni processes>'
+  echo 'startUnpack.sh <Nb Unp & Moni processes> <full filename pattern list>'
+  echo 'startUnpack.sh <Nb Unp & Moni processes> <filename pattern> <folder_path>'
+  echo 'startUnpack.sh <Nb Unp & Moni processes> "" "" <hostname(s) list>'
+  echo 'startUnpack.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS>'
+  echo 'startUnpack.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s>'
+  echo 'startUnpack.sh <Nb Unp & Moni processes> "" "" <hostname(s) list> <Hist publish freq. in TS> <Min Hist pub. in s> <Max Hist pub. in s>'
   _filename=""
   _dirname=""
   _hostname="localhost"
@@ -96,11 +96,7 @@ echo "Buffer size for singleton devices $_singBuffSz"
 
 SAMPLER="RepReqTsSampler"
 SAMPLER+=" --id sampler1"
-#SAMPLER+=" --max-timeslices 0"
-#SAMPLER+=" --max-timeslices 10"
-#SAMPLER+=" --max-timeslices 100"
 SAMPLER+=" --max-timeslices 300"
-#SAMPLER+=" --max-timeslices 1000"
 SAMPLER+=" --severity info"
 #SAMPLER+=" --flib-port 10"
 if [ "$_hostname" != "" ]; then
@@ -136,40 +132,84 @@ while (( _iMoni < _nbmoni )); do
   (( _iMoni += 1 ))
   (( _iPort = 11680 + _iMoni ))
 
- ### UNPACKER="MqUnpack" # old version
-  UNPACKER="MqDevUnpack"  #new algo version
+  UNPACKER="MqDevUnpack"  
   UNPACKER+=" --id unp$_iMoni"
   UNPACKER+=" --severity info"
   #UNPACKER+=" --severity debug"
-  UNPACKER+=" --Setup $_setup_name"
   UNPACKER+=" --RunId $_run_id"
-  UNPACKER+=" --IgnOverMs 1"
-  UNPACKER+=" --SetTimeOffs kSTS,-2221"
-  UNPACKER+=" --SetTimeOffs kMUCH,-885"
-  UNPACKER+=" --SetTimeOffs kTRD,0"
-  UNPACKER+=" --SetTimeOffs kTRD2D,-1800"
-  UNPACKER+=" --SetTimeOffs kTOF,-1220"
-  UNPACKER+=" --SetTimeOffs kRICH,254800"
-  UNPACKER+=" --SetTimeOffs kPSD,0"
-  UNPACKER+=" --PubFreqTs $_pubfreqts"
-  UNPACKER+=" --PubTimeMin $_pubminsec"
-  UNPACKER+=" --PubTimeMax $_pubmaxsec"
   UNPACKER+=" --TsNameOut unpts$_iMoni"
   UNPACKER+=" --channel-config name=ts-request,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11555"
-  UNPACKER+=" --channel-config name=parameters,type=req,method=connect,transport=zeromq,address=tcp://127.0.0.1:11005,rateLogging=0"
   UNPACKER+=" --channel-config name=unpts$_iMoni,type=push,method=bind,transport=zeromq,address=tcp://127.0.0.1:$_iPort"
-#  UNPACKER+=" --channel-config name=commands,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11007"
-  UNPACKER+=" --channel-config name=histogram-in,type=pub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11666"
   UNPACKER+=" --transport zeromq"
   # Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
   # with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
   UNPACKER_LOG="unp$_iMoni"
   UNPACKER_LOG+="_$LOGFILETAG"
-  xterm -l -lf $UNPACKER_LOG -geometry 132x23+400+$_yOffset -hold -e @CMAKE_BINARY_DIR@/bin/MQ/mcbm/$UNPACKER &
-
+  xterm -l -lf $UNPACKER_LOG -geometry 132x23+400+$_yOffset -hold -e @CMAKE_BINARY_DIR@/bin/mq/$UNPACKER &
+
+  TRIGGER="MqDevTrigger"
+  TRIGGER+=" --id trigger$_iMoni"
+  TRIGGER+=" --severity info"
+  #TRIGGER+=" --severity debug"
+###  TRIGGER+=" --TriggerDet Tof"
+  TRIGGER+=" --TriggerDet Sts"
+  TRIGGER+=" --TriggerWin 50.0"
+  TRIGGER+=" --TriggerMinDigis 20"
+  TRIGGER+=" --TriggerDeadTime 10.0"
+  TRIGGER+=" --TsNameIn unpts$_iMoni"
+  TRIGGER+=" --TriggerNameOut trigger"
+  TRIGGER+=" --channel-config name=unpts$_iMoni,type=pull,method=connect,transport=zeromq,address=tcp://127.0.0.1:$_iPort"
+  TRIGGER+=" --channel-config name=trigger,type=push,method=connect,transport=zeromq,address=tcp://127.0.0.1:11556"
+  TRIGGER+=" --transport zeromq"
+  # Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
+  # with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
+  TRIGGER_LOG="trigger$_iMoni"
+  TRIGGER_LOG+="_$LOGFILETAG"
+  xterm -l -lf $TRIGGER_LOG -geometry 80x23+800+$_yOffset -hold -e @CMAKE_BINARY_DIR@/bin/mq/$TRIGGER &
+
+  EVTBUILDER="MqDevBuildEvents"
+  EVTBUILDER+=" --id build$_iMoni"
+  EVTBUILDER+=" --severity info"
+  #EVTBUILDER+=" --severity debug"
+  EVTBUILDER+=" --OutFileName events.root"
+  EVTBUILDER+=" --SetEvbuildWin kSts,-100,100"
+##  EVTBUILDER+=" --SetEvbuildWin kTrd,-250,250"
+##  EVTBUILDER+=" --SetEvbuildWin kTof,-150,150" # To get T0 Digis (seed + close-by digis) in the event
+##  EVTBUILDER+=" --SetEvbuildWin kRich,-100,100"
+##  EVTBUILDER+=" --SetEvbuildWin kPsd,-100,100"
+  EVTBUILDER+=" --TrigNameIn trigger"
+  EVTBUILDER+=" --EvtNameOut events"
+  EVTBUILDER+=" --channel-config name=trigger,type=pull,method=bind,transport=zeromq,address=tcp://127.0.0.1:11556"
+  EVTBUILDER+=" --channel-config name=events,type=push,method=connect,transport=zeromq,address=tcp://127.0.0.1:11557"
+  EVTBUILDER+=" --transport zeromq"
+  # Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
+  # with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
+  EVTBUILDER_LOG="build$_iMoni"
+  EVTBUILDER_LOG+="_$LOGFILETAG"
+  xterm -l -lf $EVTBUILDER_LOG -geometry 80x23+800+$_yOffset -hold -e @CMAKE_BINARY_DIR@/bin/mq/$EVTBUILDER &
 
 done
 
+EVTSINK="MqDevEventSink"
+EVTSINK+=" --id evtsink1"
+EVTSINK+=" --severity info"
+#EVTSINK+=" --severity debug"
+#EVTSINK+=" --StoreFullTs 1"
+EVTSINK+=" --OutFileName mcbm_digis_events.root"
+EVTSINK+=" --FillHistos false"
+EVTSINK+=" --PubFreqTs $_pubfreqts"
+EVTSINK+=" --PubTimeMin $_pubminsec"
+EVTSINK+=" --PubTimeMax $_pubmaxsec"
+EVTSINK+=" --EvtNameIn events"
+EVTSINK+=" --channel-config name=events,type=pull,method=bind,transport=zeromq,address=tcp://127.0.0.1:11557"
+EVTSINK+=" --channel-config name=missedts,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11006"
+EVTSINK+=" --channel-config name=commands,type=sub,method=connect,transport=zeromq,address=tcp://127.0.0.1:11007"
+EVTSINK+=" --channel-config name=histogram-in,type=sub,method=bind,transport=zeromq,address=tcp://127.0.0.1:11666"
+# Replaces log filename Xterm.log.hostname.yyyy.mm.dd.hh.mm.ss.XXXXXX
+# with ProcessName_hostname_yyyy_mm_dd_hh_mm_ss.log
+EVTSINK_LOG="evtsink1_$LOGFILETAG"
+xterm -l -lf $EVTSINK_LOG -geometry 80x23+1200+0 -hold -e @CMAKE_BINARY_DIR@/bin/mq/$EVTSINK &
+
 PARAMETERSERVER="parmq-server"
 PARAMETERSERVER+=" --id parmq-server"
 PARAMETERSERVER+=" --severity info"