diff --git a/algo/base/PartitionedSpan.h b/algo/base/PartitionedSpan.h
index db330510ef11f4933a5e6e6c0624900bb9ed734d..c626b75552aa7632a3edbf05160513d33f2d2f93 100644
--- a/algo/base/PartitionedSpan.h
+++ b/algo/base/PartitionedSpan.h
@@ -156,7 +156,7 @@ namespace cbm::algo
     void EnsureDimensions() const
     {
       if (fOffsets.size() - 1 != fAdresses.size()) {
-        throw std::runtime_error("PartitionedSpan: fOffsets.size() != fAdresses.size()");
+        throw std::runtime_error("PartitionedSpan: fOffsets.size() - 1 != fAdresses.size()");
       }
       if (fOffsets.front() != 0) throw std::runtime_error("PartitionedSpan: fOffsets.front() != 0");
       if (fOffsets.back() != fData.size()) {
diff --git a/algo/base/PartitionedVector.h b/algo/base/PartitionedVector.h
index 119c2518ad15e02e20e88b727c53ebb6da1bedd9..6aa91585c03692b7913bb0c8600a86a36eaa6691 100644
--- a/algo/base/PartitionedVector.h
+++ b/algo/base/PartitionedVector.h
@@ -35,7 +35,7 @@ namespace cbm::algo
     /**
      * @brief Default constructor. Creates an empty vector.
      */
-    PartitionedVector() : fData(), fOffsets({0}), fAdresses() { EnsureDimensions(); }
+    PartitionedVector() : fData(), fOffsets({0}), fAddresses() { EnsureDimensions(); }
 
     /**
      * @brief Constructor. Creates a vector with n partitions.
@@ -49,7 +49,7 @@ namespace cbm::algo
     PartitionedVector(Container_t&& data, gsl::span<const size_t> sizes, gsl::span<const u32> addresses)
       : fData(std::move(data))
       , fOffsets()
-      , fAdresses(addresses.begin(), addresses.end())
+      , fAddresses(addresses.begin(), addresses.end())
     {
       ComputeOffsets(sizes);
       EnsureDimensions();
@@ -62,22 +62,72 @@ namespace cbm::algo
     PartitionedVector(const PartitionedVector<T, OtherAllocator>& other)
       : fData(other.Data().begin(), other.Data().end())
       , fOffsets(other.Offsets())
-      , fAdresses(other.Addresses())
+      , fAddresses(other.Addresses())
     {
       // TODO: this check is overkill? We already know that the dimensions are correct,
       // since they were already checked in the other vector
       EnsureDimensions();
     }
 
+    /**
+     * @brief Copy constructor for a given type (to satisfy the rule of five)
+     */
+    PartitionedVector(const PartitionedVector<T, Allocator>& other)
+      : fData(other.Data().begin(), other.Data().end())
+      , fOffsets(other.Offsets())
+      , fAddresses(other.Addresses())
+    {
+      EnsureDimensions();
+    }
+
+    /**
+     * @brief Move constructor 
+     */
+    PartitionedVector(PartitionedVector<T, Allocator>&& other)
+      : fData(std::move(other.fData))
+      , fOffsets(std::move(other.fOffsets))
+      , fAddresses(std::move(other.fAddresses))
+    {
+      EnsureDimensions();
+      other.fOffsets = {0};
+    }
+
     template<typename U>
     PartitionedVector(PartitionedSpan<U> other)
       : fData(other.Data().begin(), other.Data().end())
       , fOffsets(other.Offsets().begin(), other.Offsets().end())
-      , fAdresses(other.Addresses().begin(), other.Addresses().end())
+      , fAddresses(other.Addresses().begin(), other.Addresses().end())
     {
       EnsureDimensions();
     }
 
+    /**
+     * @brief Copy assignment operator
+     */
+    PartitionedVector& operator=(const PartitionedVector<T, Allocator>& other)
+    {
+      if (this != &other) {
+        fData      = other.fData;
+        fOffsets   = other.fOffsets;
+        fAddresses = other.fAddresses;
+      }
+      return *this;
+    }
+
+    /**
+     * @brief Move assignment operator
+     */
+    PartitionedVector& operator=(PartitionedVector<T, Allocator>&& other)
+    {
+      if (this != &other) {
+        fData          = std::move(other.fData);
+        fOffsets       = std::move(other.fOffsets);
+        fAddresses     = std::move(other.fAddresses);
+        other.fOffsets = {0};
+      }
+      return *this;
+    }
+
     /**
      * @brief Access data at partition i.
      */
@@ -102,7 +152,18 @@ namespace cbm::algo
     u32 Address(size_t i) const
     {
       EnsureBounds(i);
-      return fAdresses[i];
+      return fAddresses[i];
+    }
+
+    /**
+     * @brief Clears the vector 
+     */
+    void Clear()
+    {
+      fData.clear();
+      fOffsets.clear();
+      fOffsets = {0};
+      fAddresses.clear();
     }
 
     /**
@@ -111,7 +172,7 @@ namespace cbm::algo
     std::pair<gsl::span<T>, u32> Partition(size_t i)
     {
       EnsureBounds(i);
-      return std::pair<gsl::span<T>, u32>(UnsafePartitionSpan(i), fAdresses[i]);
+      return std::pair<gsl::span<T>, u32>(UnsafePartitionSpan(i), fAddresses[i]);
     }
 
     /**
@@ -120,13 +181,13 @@ namespace cbm::algo
     std::pair<gsl::span<const T>, u32> Partition(size_t i) const
     {
       EnsureBounds(i);
-      return std::pair<gsl::span<const T>, u32>(UnsafePartitionSpan(i), fAdresses[i]);
+      return std::pair<gsl::span<const T>, u32>(UnsafePartitionSpan(i), fAddresses[i]);
     }
 
     /**
      * @brief Get the number of partitions.
      */
-    size_t NPartitions() const { return fAdresses.size(); }
+    size_t NPartitions() const { return fAddresses.size(); }
 
     /**
      * @brief Get the size of partition i.
@@ -160,22 +221,23 @@ namespace cbm::algo
     /**
      * @brief Get the addresses.
      */
-    const std::vector<u32>& Addresses() const { return fAdresses; }
+    const std::vector<u32>& Addresses() const { return fAddresses; }
 
     /**
      * @brief Get the underlying offsets.
      */
     const std::vector<size_t>& Offsets() const { return fOffsets; }
 
+
    private:
     Container_t fData;             //< Data
     std::vector<size_t> fOffsets;  // < Offsets of the partitions in fData
-    std::vector<u32> fAdresses;    //< Hardware addresses of the partitions
+    std::vector<u32> fAddresses;   //< Hardware addresses of the partitions
 
     void EnsureDimensions() const
     {
-      if (fOffsets.size() - 1 != fAdresses.size()) {
-        throw std::runtime_error("PartitionedVector: fOffsets.size() != fAdresses.size()");
+      if (fOffsets.size() - 1 != fAddresses.size()) {
+        throw std::runtime_error("PartitionedVector: fOffsets.size() - 1 != fAddresses.size()");
       }
       if (fOffsets.front() != 0) {
         throw std::runtime_error("PartitionedVector: fOffsets.front() != 0");
@@ -187,7 +249,7 @@ namespace cbm::algo
 
     void EnsureBounds(size_t i) const
     {
-      if (i >= fAdresses.size()) throw std::out_of_range("PartitionedVector: index out of bounds");
+      if (i >= fAddresses.size()) throw std::out_of_range("PartitionedVector: index out of bounds");
     }
 
     void ComputeOffsets(gsl::span<const size_t> sizes)
@@ -216,7 +278,7 @@ namespace cbm::algo
     {
       ar& fData;
       ar& fOffsets;
-      ar& fAdresses;
+      ar& fAddresses;
     }
   };
 
diff --git a/algo/ca/core/CMakeLists.txt b/algo/ca/core/CMakeLists.txt
index 2be924997474f03ae9311ec060bd857d21cf725a..b680cb436d8acb250fcde0d8ae2603bb3bd9f950 100644
--- a/algo/ca/core/CMakeLists.txt
+++ b/algo/ca/core/CMakeLists.txt
@@ -1,3 +1,4 @@
+# FIXME: SZh 2.4.2025: Rewrite the file in the same manner as for KfCore
 set(INCLUDE_DIRECTORIES
   ${CMAKE_CURRENT_SOURCE_DIR}
   ${CMAKE_CURRENT_SOURCE_DIR}/utils
diff --git a/algo/ca/core/utils/CaVector.h b/algo/ca/core/utils/CaVector.h
index 467fda792a14dab157f7197e44c40b27ba4bf18e..066ce75fd63588aaf4cac8b4d0dd1c019e1fbc53 100644
--- a/algo/ca/core/utils/CaVector.h
+++ b/algo/ca/core/utils/CaVector.h
@@ -18,6 +18,7 @@
 #include <boost/serialization/string.hpp>
 #include <boost/serialization/vector.hpp>
 
+#include <memory>
 #include <sstream>
 
 namespace cbm::algo::ca
@@ -39,7 +40,20 @@ namespace cbm::algo::ca
     friend class boost::serialization::access;
 
    public:
-    typedef std::vector<T> Tbase;
+    using Tbase                  = std::vector<T>;
+    using value_type             = T;
+    using allocator_type         = typename Tbase::allocator_type;
+    using pointer                = typename std::allocator_traits<allocator_type>::pointer;
+    using const_pointer          = typename std::allocator_traits<allocator_type>::const_pointer;
+    using reference              = value_type&;
+    using const_reference        = const value_type&;
+    using size_type              = typename Tbase::size_type;
+    using difference_type        = typename Tbase::difference_type;
+    using iterator               = typename Tbase::iterator;
+    using const_iterator         = typename Tbase::const_iterator;
+    using reverse_iterator       = std::reverse_iterator<iterator>;
+    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
 
     /// \brief Generic constructor from vairadic parameter list
     template<typename... Tinput>
@@ -258,7 +272,7 @@ namespace cbm::algo::ca
     using Tbase::reserve;
     using Tbase::shrink_to_fit;
     using Tbase::size;
-    using typename Tbase::iterator;
+
 
    private:
     std::string fName{"no name"};  ///< Name of the vector
diff --git a/algo/detectors/bmon/Hit.h b/algo/detectors/bmon/Hit.h
index e4e1aef243769e409fc0b8c06466b78548a80461..26e35bb18591f4b0f2a80867ca06a216ebd2a83c 100644
--- a/algo/detectors/bmon/Hit.h
+++ b/algo/detectors/bmon/Hit.h
@@ -22,6 +22,9 @@ namespace cbm::algo::bmon
   /// \brief  A BMON hit
   class Hit {
    public:
+    /// \brief Default constructor
+    Hit() = default;
+
     /// \brief Constructor from a single digi
     /// \param address  Address of the diamond
     /// \param digi     A digi
diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx
index 79784707ea990ca10e78cc88ec1b83c2512481e5..1554da152a372b06c12fad0c227dcff9878905c9 100644
--- a/algo/global/Reco.cxx
+++ b/algo/global/Reco.cxx
@@ -466,6 +466,7 @@ RecoResults Reco::Run(const fles::Timeslice& ts)
       results.tracks             = std::move(recoData.tracks);
       results.trackStsHitIndices = std::move(trackingOutput.stsHitIndices);
       results.trackTofHitIndices = std::move(trackingOutput.tofHitIndices);
+      results.trackTrdHitIndices = std::move(trackingOutput.trdHitIndices);
     }
     if (Opts().HasOutput(RecoData::DigiEvent)) results.events = std::move(events);
     if (Opts().HasOutput(RecoData::Cluster)) results.stsClusters = std::move(recoData.stsClusters);
diff --git a/algo/global/StorableRecoResults.cxx b/algo/global/StorableRecoResults.cxx
index 5df67c5a68d11e812dafb4f01e281f25095490c8..22b072eb30b4e716295f590c911f7a05a76530a3 100644
--- a/algo/global/StorableRecoResults.cxx
+++ b/algo/global/StorableRecoResults.cxx
@@ -21,6 +21,7 @@ size_t StorableRecoResults::SizeBytes() const
   }
 
   size += fStsClusters.SizeBytes();
+  size += fBmonHits.SizeBytes();
   size += fStsHits.SizeBytes();
   size += fTofHits.SizeBytes();
   size += fTrdHits.SizeBytes();
diff --git a/algo/global/StorableRecoResults.h b/algo/global/StorableRecoResults.h
index 5560b7d1ad1998bfacc2b35e0f64335acc571820..3dfd208b18b30ffe95683e6a9c07d57be8f50db0 100644
--- a/algo/global/StorableRecoResults.h
+++ b/algo/global/StorableRecoResults.h
@@ -6,6 +6,7 @@
 
 #include "CbmDigiEvent.h"
 #include "PartitionedVector.h"
+#include "bmon/Hit.h"
 #include "ca/core/data/CaTrack.h"
 #include "ca/core/utils/CaVector.h"
 #include "sts/Cluster.h"
@@ -76,6 +77,9 @@ namespace cbm::algo
     PartitionedVector<sts::Cluster>& StsClusters() { return fStsClusters; }
     const PartitionedVector<sts::Cluster>& StsClusters() const { return fStsClusters; }
 
+    PartitionedVector<bmon::Hit>& BmonHits() { return fBmonHits; }
+    const PartitionedVector<bmon::Hit>& BmonHits() const { return fBmonHits; }
+
     PartitionedVector<sts::Hit>& StsHits() { return fStsHits; }
     const PartitionedVector<sts::Hit>& StsHits() const { return fStsHits; }
 
@@ -94,6 +98,9 @@ namespace cbm::algo
     TrackHitIndexContainer_t& TrackTofHitIndices() { return fTrackTofHitIndices; }
     const TrackHitIndexContainer_t& TrackTofHitIndices() const { return fTrackTofHitIndices; }
 
+    TrackHitIndexContainer_t& TrackTrdHitIndices() { return fTrackTrdHitIndices; }
+    const TrackHitIndexContainer_t& TrackTrdHitIndices() const { return fTrackTrdHitIndices; }
+
    private:
     uint64_t fTsIndex     = UINT64_MAX;
     uint64_t fTsStartTime = UINT64_MAX;
@@ -112,6 +119,7 @@ namespace cbm::algo
 
     // Local Reconstruction output
     PartitionedVector<sts::Cluster> fStsClusters;
+    PartitionedVector<bmon::Hit> fBmonHits;
     PartitionedVector<sts::Hit> fStsHits;
     PartitionedVector<tof::Hit> fTofHits;
     PartitionedVector<trd::Hit> fTrdHits;
@@ -127,6 +135,10 @@ namespace cbm::algo
     /// \note  index: [trkID][hitID], value: pair(partitionID, hitPartitionID)
     TrackHitIndexContainer_t fTrackTofHitIndices;
 
+    /// \brief TRD hit indices of tracks
+    /// \note  index: [trkID][hitID], value: pair(partitionID, hitPartitionID)
+    TrackHitIndexContainer_t fTrackTrdHitIndices;
+
     friend class boost::serialization::access;
 
     template<class Archive>
@@ -146,6 +158,7 @@ namespace cbm::algo
       ar& fDigiEvents;
 
       ar& fStsClusters;
+      ar& fBmonHits;
       ar& fStsHits;
       ar& fTofHits;
       ar& fTrdHits;
@@ -153,6 +166,7 @@ namespace cbm::algo
       ar& fTracks;
       ar& fTrackStsHitIndices;
       ar& fTrackTofHitIndices;
+      ar& fTrackTrdHitIndices;
     }
   };
 
diff --git a/algo/kf/core/CMakeLists.txt b/algo/kf/core/CMakeLists.txt
index 0c2168e867a71397ae6f1e2a18c408a03375d262..1d3bfb4b2fd89504d7aaa0b1f534f48c7dc9f181 100644
--- a/algo/kf/core/CMakeLists.txt
+++ b/algo/kf/core/CMakeLists.txt
@@ -63,37 +63,32 @@ target_link_libraries(KfCore
 
 ##### Offline version without the NO_ROOT in order to get standard logger! #############################################
 if (NOT CBM_ONLINE_STANDALONE)
-  add_library(KfCoreOffline SHARED ${SRCS})
-
-  target_include_directories(KfCoreOffline
-    PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/algo
-           ${CMAKE_CURRENT_SOURCE_DIR}/data
-           ${CMAKE_CURRENT_SOURCE_DIR}/geo
-           ${CMAKE_CURRENT_SOURCE_DIR}/pars
-           ${CMAKE_CURRENT_SOURCE_DIR}/utils
-           ${CMAKE_CURRENT_SOURCE_DIR}
+  set(LIBRARY_NAME KfCoreOffline)
+  set(LINKDEF ${LIBRARY_NAME}LinkDef.h)
+  list(APPEND HEADERS data/KfTrackParam.h
+    
+  )
+  set(LIBRARY_NAME KfCoreOffline)
+  set(PUBLIC_DEPENDENCIES
+    Vc::Vc
+    OnlineDataLog          # needed for the logger?
+    FairLogger::FairLogger
+    ROOT::Core  # for ClassDef
+  )
+
+  set(PRIVATE_DEPENDENCIES
+    Boost::serialization
+    fmt::fmt
+    external::yaml-cpp
   )
 
-  target_link_libraries(KfCoreOffline
-                PUBLIC  Vc::Vc
-                        OnlineDataLog          # needed for the logger?
-                        FairLogger::FairLogger
-               PRIVATE  Boost::serialization
-                        fmt::fmt
-                        external::yaml-cpp
-                       )
-  install(TARGETS KfCoreOffline DESTINATION lib)
+  generate_cbm_library()
+
+  #install(TARGETS KfCoreOffline DESTINATION lib)
 endif()
 ########################################################################################################################
 
 install(TARGETS KfCore DESTINATION lib)
-install(DIRECTORY kf TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
-install(DIRECTORY kf/utils TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
-install(DIRECTORY kf/data TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
-install(DIRECTORY kf/geo TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
-install(DIRECTORY kf/algo TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
-install(DIRECTORY kf/pars TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
-
 install(
   FILES
     KfFramework.h
diff --git a/algo/kf/core/KfCoreOfflineLinkDef.h b/algo/kf/core/KfCoreOfflineLinkDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..80fd6997451e91a505c63b4d0af50cfa47a2c53d
--- /dev/null
+++ b/algo/kf/core/KfCoreOfflineLinkDef.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class cbm::algo::kf::TrackParamBaseScalar<float> + ;
+#pragma link C++ class cbm::algo::kf::TrackParamBaseScalar<double> + ;
+
+#pragma link C++ class cbm::algo::kf::TrackParamBase<float> + ;
+#pragma link C++ class cbm::algo::kf::TrackParamBase<double> + ;
+#pragma link C++ class cbm::algo::kf::TrackParamBase<Vc_1::Vector<float, Vc_1::VectorAbi::Sse> > + ;
+
+#pragma link C++ class cbm::algo::kf::TrackParam<float> + ;
+#pragma link C++ class cbm::algo::kf::TrackParam<double> + ;
+#pragma link C++ class cbm::algo::kf::TrackParam<Vc_1::Vector<float, Vc_1::VectorAbi::Sse> > + ;
+#endif
diff --git a/algo/kf/core/data/KfTrackParam.h b/algo/kf/core/data/KfTrackParam.h
index d439bbd8c8a6424ed0765317c4cf003c63876604..5163404cc47f411ed45741165e13a476995939b0 100644
--- a/algo/kf/core/data/KfTrackParam.h
+++ b/algo/kf/core/data/KfTrackParam.h
@@ -19,6 +19,10 @@
 
 #include <string>
 
+#if !defined(NO_ROOT) && !XPU_IS_HIP_CUDA
+#include <Rtypes.h>  // for ClassDef
+#endif
+
 namespace cbm::algo::kf
 {
   /// \class cbm::algo::kf::TrackParamBase
@@ -619,6 +623,10 @@ namespace cbm::algo::kf
     T fChiSqTime{0.};  ///< chi^2 of track fit, time measurements
     T fNdfTime{0.};    ///< NDF of track fit, time measurements
 
+#if !defined(NO_ROOT) && !XPU_IS_HIP_CUDA
+    ClassDefNV(TrackParamBase, 1);
+#endif
+
   };  // class TrackParamBase
 
 
@@ -634,6 +642,10 @@ namespace cbm::algo::kf
     /// ---------------------------------------------------------------------------------------------------------------------using
     /// \brief Gets pseudo-rapidity
     T GetEta() const { return -log(tan(this->GetTheta() * T(0.5))); }
+
+#if !defined(NO_ROOT) && !XPU_IS_HIP_CUDA
+    ClassDefNV(TrackParamBaseScalar, 1);
+#endif
   };
 
 
@@ -647,12 +659,20 @@ namespace cbm::algo::kf
   class TrackParam : public TrackParamBaseScalar<T> {
    public:
     using TrackParamBaseScalar<T>::TrackParamBaseScalar;
+
+#if !defined(NO_ROOT) && !XPU_IS_HIP_CUDA
+    ClassDefNV(TrackParam, 1);
+#endif
   };
 
   template<>
   class TrackParam<fvec> : public TrackParamBase<fvec> {
    public:
     using TrackParamBase<fvec>::TrackParamBase;
+
+#if !defined(NO_ROOT) && !XPU_IS_HIP_CUDA
+    ClassDefNV(TrackParam<fvec>, 1);
+#endif
   };
 
 
diff --git a/core/base/utils/CbmMcbmUtils.cxx b/core/base/utils/CbmMcbmUtils.cxx
index 0475abc7dca22cbac129575fd2cc7b72fe4ba907..11092a65e44949fbdfc691ffc8e67e382dfe00ce 100644
--- a/core/base/utils/CbmMcbmUtils.cxx
+++ b/core/base/utils/CbmMcbmUtils.cxx
@@ -67,7 +67,7 @@ namespace cbm
       }
       else {
         /// Missing runs, exception there to force implementation and support from users side
-        throw(std::invalid_argument(Form("RunId %d is not mapped! Please complete the map!", ulRunId)));
+        throw(std::invalid_argument(Form("RunId %lu is not mapped! Please complete the map!", ulRunId)));
       }
 
       return sSetupName;
diff --git a/macro/run/run_inspect_reco_timeslice.C b/macro/run/run_inspect_reco_timeslice.C
new file mode 100644
index 0000000000000000000000000000000000000000..53073fa5b69566bd47c4720a0ec7b167e5655053
--- /dev/null
+++ b/macro/run/run_inspect_reco_timeslice.C
@@ -0,0 +1,110 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   run_inspect_reco_timeslice.C
+/// \brief  ROOT macro to convert reconstructed data output from the online binary to a ROOT file
+/// \author Sergei Zharko <s.zharko@gsi.de>
+
+// --- Includes needed for IDE
+#include <RtypesCore.h>
+#if !defined(__CLING__)
+#include "CbmSourceRecoTimeslice.h"
+#include "CbmTaskInspectRecoTimeslice.h"
+#include "CbmTsEventHeader.h"
+
+#include <FairRunAna.h>
+#include <FairSystemInfo.h>
+
+#include <TStopwatch.h>
+#endif
+
+/// \brief Main function of the macro
+/// \param inputFileName   Name of input file
+/// \param outputFileName  Name of output file
+/// \param numTimeslices   Number of time-slices to process
+void run_inspect_reco_timeslice(TString inputFileName, TString outputFileName, size_t numTimeslices = -1)
+{
+
+  // ========================================================================
+  //          Adjust this part according to your requirements
+
+  // --- Logger settings ----------------------------------------------------
+  TString logLevel     = "INFO";
+  TString logVerbosity = "LOW";
+  // ------------------------------------------------------------------------
+
+  // -----   Environment   --------------------------------------------------
+  TString myName = "run_inspect_reco_timeslice";   // this macro's name for screen output
+  TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
+  // ------------------------------------------------------------------------
+
+
+  // -----   Timer   --------------------------------------------------------
+  TStopwatch timer;
+  timer.Start();
+  // ------------------------------------------------------------------------
+
+
+  // -----   FairRunAna   ---------------------------------------------------
+  FairRunOnline* run = new FairRunOnline();
+  run->SetEventHeader(new CbmTsEventHeader{});
+  FairSource* source = new CbmSourceRecoTimeslice(inputFileName);
+  run->SetSource(source);
+  auto sink = new FairRootFileSink(outputFileName);
+  run->SetSink(sink);
+  run->SetGenerateRunInfo(kTRUE);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Logger settings   ----------------------------------------------
+  FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data());
+  FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data());
+  // ------------------------------------------------------------------------
+
+
+  // -----   Event inspection   ---------------------------------------------
+  FairTask* inspect = new CbmTaskInspectRecoTimeslice();
+  LOG(info) << "-I- " << myName << ": Adding task " << inspect->GetName();
+  run->AddTask(inspect);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Run initialisation   -------------------------------------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Initialise run" << std::endl;
+  run->Init();
+  // ------------------------------------------------------------------------
+
+
+  // -----   Start run   ----------------------------------------------------
+  std::cout << std::endl << std::endl;
+  std::cout << "-I- " << myName << ": Starting run" << std::endl;
+  if (numTimeslices == -1)
+    run->Run(-1, 0);
+  else
+    run->Run(0, numTimeslices);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Finish   -------------------------------------------------------
+  timer.Stop();
+  FairMonitor::GetMonitor()->Print();
+  Double_t rtime = timer.RealTime();
+  Double_t ctime = timer.CpuTime();
+  std::cout << std::endl << std::endl;
+  std::cout << "Macro finished successfully." << std::endl;
+  std::cout << "Real time " << rtime << " s, CPU time " << ctime << " s" << std::endl;
+  FairSystemInfo sysInfo;
+  Float_t maxMemory = sysInfo.GetMaxMemory();
+  std::cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">";
+  std::cout << maxMemory;
+  std::cout << "</DartMeasurement>" << std::endl;
+  Float_t cpuUsage = ctime / rtime;
+  std::cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">";
+  std::cout << cpuUsage;
+  std::cout << "</DartMeasurement>" << std::endl;
+  // ------------------------------------------------------------------------
+
+
+}  // End of main macro function
diff --git a/reco/L1/L1LinkDef.h b/reco/L1/L1LinkDef.h
index 159d3d6888444ccb3aa5a1c9dcb7792f552f5256..1976a6d74a06ea6306f81d7835aa03836c738291 100644
--- a/reco/L1/L1LinkDef.h
+++ b/reco/L1/L1LinkDef.h
@@ -43,5 +43,8 @@
 //#pragma link C++ class cbm::ca::IdealHitProducer < L1DetectorID::kTof > + ;
 #pragma link C++ class cbm::ca::IdealHitProducer + ;
 #pragma link C++ class cbm::ca::tools::MaterialHelper + ;
+#pragma link C++ class cbm::algo::ca::Vector + ;
+#pragma link C++ class cbm::algo::ca::Track + ;
+#pragma link C++ class cbm::algo::ca::Vector < cbm::algo::ca::Track > + ;
 
 #endif
diff --git a/reco/app/cbmreco/main.cxx b/reco/app/cbmreco/main.cxx
index 6dd23efc4481d3854e2f76af8d715f66528521a4..c78dbfe889ff2259fb4acc36bb4ebdcf932462da 100644
--- a/reco/app/cbmreco/main.cxx
+++ b/reco/app/cbmreco/main.cxx
@@ -45,6 +45,7 @@ std::shared_ptr<StorableRecoResults> makeStorableRecoResults(const fles::Timesli
   storable->RichDigis()  = ToStdVector(results.richDigis);
 
   storable->StsClusters() = results.stsClusters;
+  storable->BmonHits()    = results.bmonHits;
   storable->StsHits()     = results.stsHits;
   storable->TofHits()     = results.tofHits;
   storable->TrdHits()     = results.trdHits;
@@ -52,6 +53,7 @@ std::shared_ptr<StorableRecoResults> makeStorableRecoResults(const fles::Timesli
   storable->Tracks()             = results.tracks;
   storable->TrackStsHitIndices() = results.trackStsHitIndices;
   storable->TrackTofHitIndices() = results.trackTofHitIndices;
+  storable->TrackTrdHitIndices() = results.trackTrdHitIndices;
 
   return storable;
 }
@@ -95,6 +97,17 @@ bool dumpArchive(const Options& opts)
 
     if (nEvents > DumpEventsPerTS) L_(info) << "...";
 
+    auto& bmonHits = recoResults->BmonHits();
+    for (size_t m = 0; m < bmonHits.NPartitions(); m++) {
+      auto [hits, address] = bmonHits.Partition(m);
+      for (size_t i = 0; i < std::min(DumpHitsPerSensor, hits.size()); i++) {
+        const auto& hit = hits[i];
+        L_(info) << " - BMON Hit " << i << " sensor: " << address << "; time: " << hit.GetTime();
+      }
+    }
+
+    L_(info) << "...";
+
     auto& stsHits = recoResults->StsHits();
     for (size_t m = 0; m < stsHits.NPartitions(); m++) {
       auto [hits, address] = stsHits.Partition(m);
@@ -119,6 +132,19 @@ bool dumpArchive(const Options& opts)
 
     L_(info) << "...";
 
+    auto trdHits = recoResults->TrdHits();
+    for (size_t m = 0; m < trdHits.NPartitions(); m++) {
+      auto [hits, address] = trdHits.Partition(m);
+      for (size_t i = 0; i < std::min(DumpHitsPerSensor, hits.size()); i++) {
+        const auto& hit = hits[i];
+        L_(info) << " - TRD Hit " << i << " sensor: " << address << "; time: " << hit.Time() << ", X: " << hit.X()
+                 << ", Y: " << hit.Y() << ", Z: " << hit.Z();
+      }
+    }
+
+    L_(info) << "...";
+
+
     auto& tracks = recoResults->Tracks();
     for (size_t t = 0; t < std::min(tracks.size(), DumpTracksPerTS); t++) {
       const auto& track = tracks[t];
diff --git a/reco/steer/CMakeLists.txt b/reco/steer/CMakeLists.txt
index 83a145c5789e2fbe4639b598e7f22086008a4b73..b40e6de6754cb9d4978ec0feb11c12b425d7c9f5 100644
--- a/reco/steer/CMakeLists.txt
+++ b/reco/steer/CMakeLists.txt
@@ -10,6 +10,7 @@ set(SRCS
   CbmRecoUnpack.cxx
   CbmSourceDigiTimeslice.cxx
   CbmSourceDigiEvents.cxx
+  CbmSourceRecoTimeslice.cxx
   CbmSourceTsArchive.cxx
   CbmOnlineParWrite.cxx
   )
diff --git a/reco/steer/CbmRecoSteerLinkDef.h b/reco/steer/CbmRecoSteerLinkDef.h
index 24a33374ea176ace08d911cd4f0b4ef9f42db94f..a161c132f6cd2cf3a73c3bd823f132d21dbaabcb 100644
--- a/reco/steer/CbmRecoSteerLinkDef.h
+++ b/reco/steer/CbmRecoSteerLinkDef.h
@@ -12,6 +12,12 @@
 #pragma link C++ class CbmRecoUnpack + ;
 #pragma link C++ class CbmSourceDigiTimeslice + ;
 #pragma link C++ class CbmSourceDigiEvents + ;
+#pragma link C++ class CbmSourceRecoTimeslice + ;
 #pragma link C++ class CbmSourceTsArchive + ;
+#pragma link C++ class cbm::algo::PartitionedVector < cbm::algo::bmon::Hit > + ;
+#pragma link C++ class cbm::algo::PartitionedVector < cbm::algo::sts::Hit > + ;
+#pragma link C++ class cbm::algo::PartitionedVector < cbm::algo::trd::Hit > + ;
+#pragma link C++ class cbm::algo::PartitionedVector < cbm::algo::tof::Hit > + ;
+#pragma link C++ class cbm::algo::ca::Vector < std::vector < std::pair < unsigned int, unsigned int > > > + ;
 
 #endif /* __CINT__ */
diff --git a/reco/steer/CbmSourceRecoTimeslice.cxx b/reco/steer/CbmSourceRecoTimeslice.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a94565dfcb89715b35a14933601ac87994429c43
--- /dev/null
+++ b/reco/steer/CbmSourceRecoTimeslice.cxx
@@ -0,0 +1,183 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CbmSourceRecoTimeslice.cxx
+/// \brief  A source class for reading reconstruction results from the online processing (implementation)
+/// \author Sergei Zharko <s.zharko@gsi.de>
+/// \since  26.03.2025
+
+#include "CbmSourceRecoTimeslice.h"
+
+#include "CbmTimeSlice.h"
+#include "CbmTsEventHeader.h"
+
+#include <FairRootManager.h>
+#include <FairRun.h>
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+CbmSourceRecoTimeslice::CbmSourceRecoTimeslice(const char* fileName) : fInputFileName(fileName) {}
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void CbmSourceRecoTimeslice::Close()
+{
+  LOG(info) << "Source: closing after " << fNumTs << " timeslices";
+  ClearOutputVectors();
+}
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+Bool_t CbmSourceRecoTimeslice::Init()
+{
+  using namespace cbm::algo;
+
+  // Create input archive
+  fArchive = std::make_unique<cbm::algo::RecoResultsInputArchive>(fInputFileName);
+  LOG(info) << "Source: Reading from input archive " << fInputFileName;
+  auto desc = fArchive->descriptor();
+  LOG(info) << "      - Time created: " << desc.time_created();
+  LOG(info) << "      - Host name   : " << desc.hostname();
+  LOG(info) << "      - User name   : " << desc.username();
+
+  auto* ioman = FairRootManager::Instance();
+  if (!ioman) {
+    LOG(fatal) << "CbmSourceRecoTimeslice::Init(): FairRootManager is not defined";
+    return kFALSE;
+  }
+
+  if (!(fTsEventHeader = dynamic_cast<CbmTsEventHeader*>(FairRun::Instance()->GetEventHeader()))) {
+    LOG(fatal) << "CbmSourceRecoTimeslice::Init() no CbmTsEventHeader was added to the run. Without it, we can not "
+                  "store the UTC of the "
+                  "Timeslices correctly. Hence, this causes a fatal. Please add it in the steering macro to the Run.";
+    return kFALSE;
+  }
+
+  // TimeSlice. branch initialization
+  if (ioman->GetObject("TimeSlice.")) {
+    LOG(fatal) << "Source: Branch TimeSlice. already exists!";
+    return kFALSE;
+  }
+  else {
+    // NOTE: the max time of timeslice is 1.28e8, taken from CbmRecoUnpack.cxx
+    fTimeslice = new CbmTimeSlice(0., 1.28e8 + 1.28e6);
+    ioman->Register("TimeSlice.", "DAQ", fTimeslice, kTRUE);
+  }
+
+  auto RegisterVector = [&](auto*& vec, const char* name) -> bool {
+    if (ioman->GetObject(name)) {
+      LOG(fatal) << "Source: branch " << name << " already exists!";
+      return false;
+    }
+    ioman->RegisterAny(name, vec, kTRUE);
+    LOG(info) << "Source: registered branch " << name << " at " << vec;
+
+    return true;
+  };
+
+  // TODO: replace individual vectors with reco-timeslice objects
+  fBmonHits = new PartitionedVector<bmon::Hit>();
+  if (!RegisterVector(fBmonHits, "OnlineBmonHit")) {
+    return kFALSE;
+  }
+
+  fStsHits = new PartitionedVector<sts::Hit>();
+  if (!RegisterVector(fStsHits, "OnlineStsHit")) {
+    return kFALSE;
+  }
+
+  fTrdHits = new PartitionedVector<trd::Hit>();
+  if (!RegisterVector(fTrdHits, "OnlineTrdHit")) {
+    return kFALSE;
+  }
+
+  fTofHits = new PartitionedVector<tof::Hit>();
+  if (!RegisterVector(fTofHits, "OnlineTofHit")) {
+    return kFALSE;
+  }
+
+  fTracks = new ca::Vector<ca::Track>();
+  if (!RegisterVector(fTracks, "OnlineTrack")) {
+    return kFALSE;
+  }
+
+  fTrackStsHitIndices = new StorableRecoResults::TrackHitIndexContainer_t();
+  if (!RegisterVector(fTrackStsHitIndices, "OnlineTrackStsHitIndex")) {
+    return kFALSE;
+  }
+
+  fTrackTrdHitIndices = new StorableRecoResults::TrackHitIndexContainer_t();
+  if (!RegisterVector(fTrackTrdHitIndices, "OnlineTrackTrdHitIndex")) {
+    return kFALSE;
+  }
+
+  fTrackTofHitIndices = new StorableRecoResults::TrackHitIndexContainer_t();
+  if (!RegisterVector(fTrackTofHitIndices, "OnlineTrackTofHitIndex")) {
+    return kFALSE;
+  }
+
+  return kTRUE;
+}
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+Int_t CbmSourceRecoTimeslice::ReadEvent(UInt_t)
+{
+  // Get next timeslice data from archive. Stop run if end of archive is reached.
+  auto results = fArchive->get();
+  if (fArchive->eos()) {
+    LOG(info) << "Source: End of input archive; terminating run";
+    return 1;
+  }
+
+  // Move event data from input archive to ROOT tree
+  if (!results) {
+    LOG(error) << "Source: Failed to read RecoResults from archive";
+    return 1;
+  }
+
+  LOG(info) << "Source: reading TS " << fNumTs << ", index " << results->TsIndex() << ", start "                //
+            << results->TsStartTime() << ", contains\n"                                                         //
+            << " Hits: BMON=" << results->BmonHits().NElements() << ", STS=" << results->StsHits().NElements()  //
+            << ", TRD=" << results->TrdHits().NElements() << ", TOF=" << results->TofHits().NElements()         //
+            << "\n Tracks: " << results->Tracks().size();
+
+  fTsEventHeader->SetTsIndex(results->TsIndex());
+  fTsEventHeader->SetTsStartTime(results->TsStartTime());
+  fTimeslice->SetStartTime(results->TsStartTime());
+
+  *fBmonHits           = std::move(results->BmonHits());
+  *fStsHits            = std::move(results->StsHits());
+  *fTrdHits            = std::move(results->TrdHits());
+  *fTofHits            = std::move(results->TofHits());
+  *fTracks             = std::move(results->Tracks());
+  *fTrackStsHitIndices = std::move(results->TrackStsHitIndices());
+  *fTrackTrdHitIndices = std::move(results->TrackTrdHitIndices());
+  *fTrackTofHitIndices = std::move(results->TrackTofHitIndices());
+
+  ++fNumTs;
+
+  return 0;
+}
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void CbmSourceRecoTimeslice::ClearOutputVectors()
+{
+  fBmonHits->Clear();
+  fStsHits->Clear();
+  fTrdHits->Clear();
+  fTofHits->Clear();
+  fTracks->clear();
+  fTrackStsHitIndices->clear();
+  fTrackTrdHitIndices->clear();
+  fTrackTofHitIndices->clear();
+}
+
+
+ClassImp(CbmSourceRecoTimeslice);
diff --git a/reco/steer/CbmSourceRecoTimeslice.h b/reco/steer/CbmSourceRecoTimeslice.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d0b907a6e508e3cc4c9d01d105291eef01e9375
--- /dev/null
+++ b/reco/steer/CbmSourceRecoTimeslice.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CbmSourceRecoTimeslice.h
+/// \brief  A source class for reading reconstruction results from the online processing
+/// \author Sergei Zharko <s.zharko@gsi.de>
+/// \since  26.03.2025
+
+#pragma once
+
+#include "RecoResultsInputArchive.h"
+
+#include <FairSource.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+class CbmTimeSlice;
+class CbmTsEventHeader;
+
+/// \class CbmSourceRecoTimeslice
+/// \brief Source class for reading reconstruction results from the online processing
+class CbmSourceRecoTimeslice : public FairSource {
+ public:
+  /// \brief  Constructor
+  /// \param  filename  Name of the input file
+  CbmSourceRecoTimeslice(const char* filename = "");
+
+  /// \brief  Copy constructor
+  CbmSourceRecoTimeslice(const CbmSourceRecoTimeslice&) = delete;
+
+  /// \brief  Move constructor
+  CbmSourceRecoTimeslice(CbmSourceRecoTimeslice&&) = delete;
+
+  /// \brief  Destructor
+  virtual ~CbmSourceRecoTimeslice() = default;
+
+  /// \brief  Copy assignment operator
+  CbmSourceRecoTimeslice& operator=(const CbmSourceRecoTimeslice&) = delete;
+
+  /// \brief  Move assignment operator
+  CbmSourceRecoTimeslice& operator=(CbmSourceRecoTimeslice&&) = delete;
+
+  /// \brief  Closes the source in the end of the run
+  virtual void Close();
+
+  /// \brief  Gets source type
+  /// \return The source type (FairSource::Source_Type)
+  virtual Source_Type GetSourceType() { return fSourceType; }
+
+  /// \brief  Initializes the source
+  virtual Bool_t Init();
+
+  /// \brief  Initializes unpackers (forced by the base class, not relevant)
+  virtual Bool_t InitUnpackers() { return kTRUE; }
+
+  /// \brief  Reads one timeslice from file
+  virtual Int_t ReadEvent(UInt_t = 0);
+
+  /// \brief  Re-initialize unpackers (forced by the base class, not relevant)
+  virtual Bool_t ReInitUnpackers() { return kTRUE; }
+
+  /// \brief  Resets the instance (forced by the base class, not relevant)
+  virtual void Reset() {}
+
+  /// \brief  Sets the unpacker parameters (forced byt the base class, not relevant)
+  virtual void SetParUnpackers() {}
+
+  /// \brief  Set the Source type
+  /// \param  type  Source type
+  void SetSourceType(Source_Type type) { fSourceType = type; }
+
+  /// \brief  Sets run ID (forced by base class, not relevant)
+  Bool_t SpecifyRunId() { return kTRUE; }
+
+ private:
+  /// \brief  Clears the output vectors
+  void ClearOutputVectors();
+
+  //* Data containers
+  cbm::algo::PartitionedVector<cbm::algo::bmon::Hit>* fBmonHits{nullptr};
+  cbm::algo::PartitionedVector<cbm::algo::sts::Hit>* fStsHits{nullptr};
+  cbm::algo::PartitionedVector<cbm::algo::trd::Hit>* fTrdHits{nullptr};
+  cbm::algo::PartitionedVector<cbm::algo::tof::Hit>* fTofHits{nullptr};
+  cbm::algo::ca::Vector<cbm::algo::ca::Track>* fTracks{nullptr};
+  cbm::algo::StorableRecoResults::TrackHitIndexContainer_t* fTrackStsHitIndices{nullptr};
+  cbm::algo::StorableRecoResults::TrackHitIndexContainer_t* fTrackTrdHitIndices{nullptr};
+  cbm::algo::StorableRecoResults::TrackHitIndexContainer_t* fTrackTofHitIndices{nullptr};
+
+  //* Auxilary variables
+
+  std::string fInputFileName{};  ///< Input file name
+
+  std::unique_ptr<cbm::algo::RecoResultsInputArchive> fArchive{nullptr};  ///< Input archive
+  CbmTimeSlice* fTimeslice{nullptr};          ///< Timeslice header (NOTE: legacy, will be deprecated soon)
+  CbmTsEventHeader* fTsEventHeader{nullptr};  ///< Timeslice event header
+
+  size_t fNumTs{0};                               ///< Timeslice counter
+  Source_Type fSourceType{Source_Type::kONLINE};  ///< A source type (use kONLINE not to skip the first timeslice)
+
+
+  ClassDef(CbmSourceRecoTimeslice, 1);
+};
diff --git a/reco/tasks/CMakeLists.txt b/reco/tasks/CMakeLists.txt
index 87daab108394cf9ced0fcbe93dfa9a49fd27467d..eff7ad33044e1a2f30ac1245f90dc42e2710bb94 100644
--- a/reco/tasks/CMakeLists.txt
+++ b/reco/tasks/CMakeLists.txt
@@ -15,6 +15,7 @@ set(SRCS
   CbmTaskEventsCloneInToOut.cxx
   CbmTaskInspectDigiEvents.cxx
   CbmTaskInspectDigiTimeslice.cxx
+  CbmTaskInspectRecoTimeslice.cxx
   CbmTaskMakeRecoEvents.cxx
   CbmTaskTriggerDigi.cxx
   CbmTaskTofHitFinder.cxx
diff --git a/reco/tasks/CbmRecoTasksLinkDef.h b/reco/tasks/CbmRecoTasksLinkDef.h
index 341f9d90653fbba5272e8bdb2a8ccfe6d72e6cd9..5a6df1f469ae0b857cd6ef1c971126434a662804 100644
--- a/reco/tasks/CbmRecoTasksLinkDef.h
+++ b/reco/tasks/CbmRecoTasksLinkDef.h
@@ -18,6 +18,7 @@
 #pragma link C++ class CbmTaskEventsCloneInToOut + ;
 #pragma link C++ class CbmTaskInspectDigiEvents + ;
 #pragma link C++ class CbmTaskInspectDigiTimeslice + ;
+#pragma link C++ class CbmTaskInspectRecoTimeslice + ;
 #pragma link C++ class CbmTaskMakeRecoEvents + ;
 #pragma link C++ class CbmTaskTofHitFinder + ;
 #pragma link C++ class CbmTaskTofClusterizer + ;
diff --git a/reco/tasks/CbmTaskInspectRecoTimeslice.cxx b/reco/tasks/CbmTaskInspectRecoTimeslice.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..cc266ba398733e7586f42c6e4ba1d0bc0fb83697
--- /dev/null
+++ b/reco/tasks/CbmTaskInspectRecoTimeslice.cxx
@@ -0,0 +1,78 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CbmTaskInspectRecoTimeslice.cxx
+/// \brief  A task to store reconstructed data into a ROOT tree (implementation)
+/// \author Sergei Zharko <s.zharko@gsi.de>
+/// \since  26.03.2025
+
+#include "CbmTaskInspectRecoTimeslice.h"
+
+#include "FairRootManager.h"
+
+#include <type_traits>
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+CbmTaskInspectRecoTimeslice::CbmTaskInspectRecoTimeslice() : FairTask("InspectOnlineRecoTimeslice") {}
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void CbmTaskInspectRecoTimeslice::Exec(Option_t*)
+{
+  LOG(info) << GetName() << ": timeslice " << fNumTs << " with " << fBmonHits->NElements() << " BMON hits, "
+            << fStsHits->NElements() << " STS hits, " << fTrdHits->NElements() << " TRD hits, " << fTofHits->NElements()
+            << " TOF hits, " << fTracks->size() << " tracks";
+
+  ++fNumTs;
+}
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void CbmTaskInspectRecoTimeslice::Finish()
+{
+  LOG(info) << "=====================================";
+  LOG(info) << GetName() << ": Run summary";
+  LOG(info) << "Timeslices : " << fNumTs;
+  LOG(info) << "=====================================";
+}
+
+
+// ---------------------------------------------------------------------------------------------------------------------
+//
+InitStatus CbmTaskInspectRecoTimeslice::Init()
+{
+  auto* ioman = FairRootManager::Instance();
+  if (!ioman) {
+    LOG(fatal) << "CbmSourceRecoTimeslice::Init(): FairRootManager is not defined";
+    return kFATAL;
+  }
+
+  LOG(info) << "==================================================";
+  LOG(info) << GetName() << ": Initialising...";
+
+  auto InitBranch = [&](const auto*& vec, const char* name) -> bool {
+    using VecPtr_t = std::remove_reference_t<decltype(vec)>;
+    vec            = ioman->InitObjectAs<VecPtr_t>(name);
+    if (!vec) {
+      LOG(error) << GetName() << ": branch " << name << " not found";
+      return false;
+    }
+    LOG(info) << GetName() << ": found branch " << name << " at " << vec;
+    return true;
+  };
+
+  InitBranch(fBmonHits, "OnlineBmonHit");
+  InitBranch(fStsHits, "OnlineStsHit");
+  InitBranch(fTrdHits, "OnlineTrdHit");
+  InitBranch(fTofHits, "OnlineTofHit");
+  InitBranch(fTracks, "OnlineTrack");
+  InitBranch(fTrackStsHitIndices, "OnlineTrackStsHitIndex");
+  InitBranch(fTrackTrdHitIndices, "OnlineTrackTrdHitIndex");
+  InitBranch(fTrackTofHitIndices, "OnlineTrackTofHitIndex");
+
+  return kSUCCESS;
+}
diff --git a/reco/tasks/CbmTaskInspectRecoTimeslice.h b/reco/tasks/CbmTaskInspectRecoTimeslice.h
new file mode 100644
index 0000000000000000000000000000000000000000..16365d5f418975bfbb7a45d22cfb00652f880ff5
--- /dev/null
+++ b/reco/tasks/CbmTaskInspectRecoTimeslice.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CbmTaskInspectRecoTimeslice.h
+/// \brief  A task to store reconstructed data into a ROOT tree
+/// \author Sergei Zharko <s.zharko@gsi.de>
+/// \since  26.03.2025
+
+#pragma once
+
+#include "RecoResults.h"
+#include "StorableRecoResults.h"
+
+#include <FairTask.h>
+
+#include <vector>
+
+
+class FairRootManager;
+
+/// \class CbmTaskInspectRecoTimeslice
+/// \brief Stores the online reco timeslice data into an output ROOT tree
+
+class CbmTaskInspectRecoTimeslice : public FairTask {
+ public:
+  /// \brief Constructor
+  CbmTaskInspectRecoTimeslice();
+
+  /// \brief Copy constructor
+  CbmTaskInspectRecoTimeslice(const CbmTaskInspectRecoTimeslice&) = delete;
+
+  /// \brief Move constructor
+  CbmTaskInspectRecoTimeslice(CbmTaskInspectRecoTimeslice&&) = delete;
+
+  /// \brief Destructor
+  virtual ~CbmTaskInspectRecoTimeslice() = default;
+
+  /// \brief Copy assignment operator
+  CbmTaskInspectRecoTimeslice& operator=(const CbmTaskInspectRecoTimeslice&) = delete;
+
+  /// \brief Move assignment operator
+  CbmTaskInspectRecoTimeslice& operator=(CbmTaskInspectRecoTimeslice&&) = delete;
+
+  /// \brief Action on the timeslice
+  virtual void Exec(Option_t* opt);
+
+  /// \brief Action in the end of the run
+  virtual void Finish();
+
+ private:
+  /// \brief Action in the beginning of the run
+  virtual InitStatus Init();
+
+  //* Data containers
+  const cbm::algo::PartitionedVector<cbm::algo::bmon::Hit>* fBmonHits{nullptr};
+  const cbm::algo::PartitionedVector<cbm::algo::sts::Hit>* fStsHits{nullptr};
+  const cbm::algo::PartitionedVector<cbm::algo::trd::Hit>* fTrdHits{nullptr};
+  const cbm::algo::PartitionedVector<cbm::algo::tof::Hit>* fTofHits{nullptr};
+  const cbm::algo::ca::Vector<cbm::algo::ca::Track>* fTracks{nullptr};
+  const cbm::algo::StorableRecoResults::TrackHitIndexContainer_t* fTrackStsHitIndices{nullptr};
+  const cbm::algo::StorableRecoResults::TrackHitIndexContainer_t* fTrackTrdHitIndices{nullptr};
+  const cbm::algo::StorableRecoResults::TrackHitIndexContainer_t* fTrackTofHitIndices{nullptr};
+  size_t fNumTs{0};
+
+  ClassDef(CbmTaskInspectRecoTimeslice, 1);
+};