diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt
index f9b85b2af271a17b9bcbfe17482fdac35b4dd24e..2937b40285365f5a0598c1955e114c3edebaf217 100644
--- a/algo/CMakeLists.txt
+++ b/algo/CMakeLists.txt
@@ -44,7 +44,6 @@ set(SRCS
   detectors/trd2d/Unpack.cxx
   detectors/rich/ReadoutConfig.cxx
   detectors/rich/Unpack.cxx
-  global/Archive.cxx
   global/Reco.cxx
   qa/DigiEventQa.cxx
   qa/Histo1D.cxx
@@ -144,6 +143,9 @@ install(
     base/RecoParams.h
     base/SubChain.h
     global/Reco.h
+    global/RecoResultsInputArchive.h
+    global/RecoResultsOutputArchive.h
+    global/StorableRecoResults.h
   DESTINATION
     include/
 )
diff --git a/algo/base/Options.cxx b/algo/base/Options.cxx
index 8a30d58307849426b188bf3c8a66b2f417759589..51486227dbaad51c5696f6175e07ad8d68b74904 100644
--- a/algo/base/Options.cxx
+++ b/algo/base/Options.cxx
@@ -63,8 +63,6 @@ Options::Options(int argc, char** argv)
   generic.add_options()
     ("output,o", po::value(&fOutputFile)->default_value("")->value_name("<file>"),
       "write results to file")
-    ("split-output-per-ts,S", po::bool_switch(&fSplitOutputPerTS)->default_value(false),
-      "Write results to file per timeslice (resulting files are named <file>_<tsnr>). Requires -o.")
     ("device,d", po::value(&fDevice)->default_value("cpu")->value_name("<device>"),
       "select device (cpu, cuda0, cuda1, hip0, ...)")
     ("log-level,l", po::value(&fLogLevel)->default_value(info)->value_name("<level>"),
@@ -88,6 +86,8 @@ Options::Options(int argc, char** argv)
       "Set number of OpenMP threads (-1 = use OMP_NUM_THREADS environment variable)")
     ("times,t", po::bool_switch(&fCollectKernelTimes)->default_value(false),
       "print kernel times")
+    ("dump-archive", po::bool_switch(&fDumpArchive)->default_value(false),
+      "Dump archive content to stdout and exit. Provide archive with '-i'. (This is a hack to quick check archive content until we have proper tooling.)")
     ("help,h",
       "produce help message")
   ;
diff --git a/algo/base/Options.h b/algo/base/Options.h
index 182a76e6d10e050928075f547540254d8ff8e540..064cc6bd3949246a140bbd3957ec4f51ef3a9dc3 100644
--- a/algo/base/Options.h
+++ b/algo/base/Options.h
@@ -4,9 +4,6 @@
 #ifndef CBM_ALGO_BASE_OPTIONS_H
 #define CBM_ALGO_BASE_OPTIONS_H
 
-#include <boost/serialization/access.hpp>
-#include <boost/serialization/version.hpp>
-
 #include <set>
 #include <string>
 #include <vector>
@@ -27,7 +24,6 @@ namespace cbm::algo
     fs::path ParamsDir() const { return fParamsDir; }
     const std::string& InputLocator() const { return fInputLocator; }
     fs::path OutputFile() const { return fOutputFile; }
-    bool SplitOutputPerTS() const { return fSplitOutputPerTS; }
     severity_level LogLevel() const { return fLogLevel; }
     fs::path LogFile() const { return fLogFile; }
     const std::string& Device() const { return fDevice; }
@@ -43,6 +39,7 @@ namespace cbm::algo
       return fNumOMPThreads > 0 ? std::make_optional(fNumOMPThreads) : std::nullopt;
     }
     const std::string& ChildId() const { return fChildId; }
+    bool DumpArchive() const { return fDumpArchive; }
 
     const std::vector<Step>& Steps() const { return fRecoSteps; }
     bool HasStep(Step step) const { return std::find(fRecoSteps.begin(), fRecoSteps.end(), step) != fRecoSteps.end(); }
@@ -63,11 +60,11 @@ namespace cbm::algo
     std::string fParamsDir;  // TODO: can we make this a std::path?
     std::string fInputLocator;
     std::string fOutputFile;
-    bool fSplitOutputPerTS = false;
     severity_level fLogLevel;
     std::string fLogFile;
     std::string fDevice;
     std::string fMonitorUri;
+    bool fDumpArchive        = false;
     bool fCollectKernelTimes = false;
     int fNumTimeslices       = -1;
     int fSkipTimeslices      = 0;
@@ -76,28 +73,6 @@ namespace cbm::algo
     std::vector<RecoData> fOutputTypes;
     std::vector<fles::Subsystem> fDetectors;
     std::string fChildId = "00";
-
-  private:  // serialization
-    friend class boost::serialization::access;
-
-    template<class Archive>
-    void serialize(Archive& ar, const unsigned int /*version*/)
-    {
-      ar& fParamsDir;
-      ar& fInputLocator;
-      ar& fOutputFile;
-      ar& fSplitOutputPerTS;
-      ar& fLogLevel;
-      ar& fLogFile;
-      ar& fDevice;
-      ar& fMonitorUri;
-      ar& fCollectKernelTimes;
-      ar& fNumTimeslices;
-      ar& fSkipTimeslices;
-      ar& fRecoSteps;
-      ar& fOutputTypes;
-      ar& fDetectors;
-    }
   };
 
 }  // namespace cbm::algo
diff --git a/algo/global/Archive.cxx b/algo/global/Archive.cxx
deleted file mode 100644
index 00cd02514ae2aec50b791c68355c7eae1830290e..0000000000000000000000000000000000000000
--- a/algo/global/Archive.cxx
+++ /dev/null
@@ -1,55 +0,0 @@
-/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Felix Weiglhofer [committer] */
-#include "Archive.h"
-
-#include "CbmDigiEvent.h"
-
-#include <boost/algorithm/string.hpp>
-#include <boost/archive/binary_iarchive.hpp>
-#include <boost/archive/binary_oarchive.hpp>
-#include <boost/serialization/vector.hpp>
-
-#include <fstream>
-#include <iomanip>
-#include <sstream>
-
-#include "log.hpp"
-
-using namespace cbm::algo;
-
-namespace ba = boost::archive;
-
-Archive::Archive(fs::path file)
-{
-  L_(info) << "Reading archive from " << file;
-  std::ifstream ifs(file.string(), std::ios::binary);
-  ba::binary_iarchive ia(ifs);
-  ia >> *this;
-}
-
-void Archive::Store(fs::path file, std::optional<size_t> tsId) const
-{
-  file = makeFileName(file, tsId);
-
-  L_(info) << "Writing archive to " << file;
-  std::ofstream ofs(file.string(), std::ios::binary);
-  ba::binary_oarchive oa(ofs);
-  oa << *this;
-}
-
-fs::path Archive::makeFileName(fs::path file, std::optional<size_t> tsId) const
-{
-  if (!tsId) return file;
-
-  // Shamelessly copied from fles::OutputArchiveSequence
-  if (file.string().find("%n") == std::string::npos) {
-    L_(warning)
-      << "Archive file name does not contain %n wildcard (timeslice number). Appending id to file name instead.";
-    file += "_%n";
-  }
-
-  std::ostringstream number;
-  number << std::setw(4) << std::setfill('0') << *tsId;
-  return boost::replace_all_copy(file.string(), "%n", number.str());
-}
diff --git a/algo/global/Archive.h b/algo/global/Archive.h
deleted file mode 100644
index cc33a837456ea41609455cfe8dfbb4e2a76ec7a8..0000000000000000000000000000000000000000
--- a/algo/global/Archive.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Felix Weiglhofer [committer] */
-#ifndef CBM_ALGO_GLOBAL_ARCHIVE_H
-#define CBM_ALGO_GLOBAL_ARCHIVE_H
-
-#include "CbmDigiEvent.h"
-
-#include "MicrosliceDescriptor.hpp"
-
-#include <boost/serialization/access.hpp>
-#include <boost/serialization/version.hpp>
-
-#include <optional>
-#include <vector>
-
-#include "ArchiveDescriptor.h"
-#include "compat/Filesystem.h"
-
-namespace cbm::algo
-{
-  class Archive {
-  public:
-    /**
-     * @brief Read Archive object from file.
-    */
-    Archive(fs::path file);
-
-    /**
-     * @brief Construct empty archive.
-    */
-    Archive(ArchiveDescriptor descriptor) : fDescriptor(descriptor) {}
-    ~Archive() = default;
-
-    /**
-     * @brief Store Archive object to file.
-    */
-    void Store(fs::path file, std::optional<size_t> tsId = {}) const;
-
-    const ArchiveDescriptor& Descriptor() const { return fDescriptor; }
-
-    std::vector<CbmDigiEvent>& TimesliceResults() { return fTimesliceResults; }
-    const std::vector<CbmDigiEvent>& TimesliceResults() const { return fTimesliceResults; }
-
-  private:
-    ArchiveDescriptor fDescriptor;
-    // TODO: Need a better storage class here, that can also store Hits, ...
-    // Will be changed with the rework of storage
-    std::vector<CbmDigiEvent> fTimesliceResults;
-
-    friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive& ar, const unsigned int /*version*/)
-    {
-      ar& fDescriptor;
-      ar& fTimesliceResults;
-    }
-
-    fs::path makeFileName(fs::path file, std::optional<size_t> tsId) const;
-  };
-}  // namespace cbm::algo
-
-BOOST_CLASS_VERSION(cbm::algo::Archive, 1)
-
-#endif
diff --git a/algo/global/ArchiveDescriptor.h b/algo/global/ArchiveDescriptor.h
deleted file mode 100644
index 64c3ecedacde1e51c1cddd589ed05ed0e46398d8..0000000000000000000000000000000000000000
--- a/algo/global/ArchiveDescriptor.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Felix Weiglhofer [committer] */
-#ifndef CBM_ALGO_GLOBAL_ARCHIVE_DESCRIPTOR_H
-#define CBM_ALGO_GLOBAL_ARCHIVE_DESCRIPTOR_H
-
-#include "System.hpp"
-
-#include <boost/serialization/access.hpp>
-#include <boost/serialization/version.hpp>
-
-#include <chrono>
-#include <string>
-
-namespace cbm::algo
-{
-
-  class ArchiveDescriptor {
-
-  public:
-    ArchiveDescriptor()
-      : fTimeCreated(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()))
-      , fHostname(fles::system::current_hostname())
-      , fUsername(fles::system::current_username())
-    {
-    }
-
-    std::time_t TimeCreated() const { return fTimeCreated; }
-    const std::string& Hostname() const { return fHostname; }
-    const std::string& Username() const { return fUsername; }
-
-  private:  // members
-    std::time_t fTimeCreated = std::time_t();
-    std::string fHostname;
-    std::string fUsername;
-
-  private:  // serialization
-    friend class boost::serialization::access;
-
-    template<class Archive>
-    void serialize(Archive& ar, const unsigned int /*version*/)
-    {
-      ar& fTimeCreated;
-      ar& fHostname;
-      ar& fUsername;
-    }
-  };
-
-}  // namespace cbm::algo
-
-#endif  // CBM_ALGO_GLOBAL_ARCHIVE_DESCRIPTOR_H
diff --git a/algo/global/RecoResultsInputArchive.h b/algo/global/RecoResultsInputArchive.h
new file mode 100644
index 0000000000000000000000000000000000000000..f47841ea69ded25beefd164f443f2d0de04468f0
--- /dev/null
+++ b/algo/global/RecoResultsInputArchive.h
@@ -0,0 +1,19 @@
+/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+#ifndef CBM_ALGO_GLOBAL_RECORESULTSINPUTARCHIVE_H
+#define CBM_ALGO_GLOBAL_RECORESULTSINPUTARCHIVE_H
+
+#include <InputArchive.hpp>
+
+#include "StorableRecoResults.h"
+
+namespace cbm::algo
+{
+
+  using RecoResultsInputArchive =
+    fles::InputArchive<StorableRecoResults, StorableRecoResults, fles::ArchiveType::RecoResultsArchive>;
+
+}  // namespace cbm::algo
+
+#endif  // CBM_ALGO_GLOBAL_RECORESULTSINPUTARCHIVE_H
diff --git a/algo/global/RecoResultsOutputArchive.h b/algo/global/RecoResultsOutputArchive.h
new file mode 100644
index 0000000000000000000000000000000000000000..a664407b433a0473610bbc69ee752128ab31ff71
--- /dev/null
+++ b/algo/global/RecoResultsOutputArchive.h
@@ -0,0 +1,19 @@
+/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+#ifndef CBM_ALGO_GLOBAL_RECO_RESULTS_OUTPUT_ARCHIVE_H
+#define CBM_ALGO_GLOBAL_RECO_RESULTS_OUTPUT_ARCHIVE_H
+
+#include <OutputArchive.hpp>
+
+#include "StorableRecoResults.h"
+
+namespace cbm::algo
+{
+
+  using RecoResultsOutputArchive =
+    fles::OutputArchive<StorableRecoResults, StorableRecoResults, fles::ArchiveType::RecoResultsArchive>;
+
+}  // namespace cbm::algo
+
+#endif  // CBM_ALGO_GLOBAL_RECO_RESULTS_OUTPUT_ARCHIVE_H
diff --git a/algo/global/StorableRecoResults.h b/algo/global/StorableRecoResults.h
new file mode 100644
index 0000000000000000000000000000000000000000..d128d9b717b92d43b95cd01b66ac33e381c545ed
--- /dev/null
+++ b/algo/global/StorableRecoResults.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+#ifndef CBM_ALGO_GLOBAL_STORABLE_RECO_RESULTS_H
+#define CBM_ALGO_GLOBAL_STORABLE_RECO_RESULTS_H
+
+#include "CbmDigiEvent.h"
+
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/vector.hpp>
+
+#include <cstdint>
+
+namespace cbm::algo
+{
+
+  class StorableRecoResults {
+
+  public:
+    /**
+     * @brief Default constructor (required by boost::serialization)
+     */
+    StorableRecoResults() = default;
+
+    StorableRecoResults(uint64_t tsIndex, uint64_t tsStartTime) : fTsIndex(tsIndex), fTsStartTime(tsStartTime) {}
+
+    /**
+     * @brief Index of the timeslice during the run
+     */
+    uint64_t TsIndex() const { return fTsIndex; }
+
+    /**
+     * @brief Start time of the timeslice
+     */
+    uint64_t TsStartTime() const { return fTsStartTime; }
+
+    std::vector<CbmDigiEvent>& DigiEvents() { return fDigiEvents; }
+    const std::vector<CbmDigiEvent>& DigiEvents() const { return fDigiEvents; }
+
+  private:
+    uint64_t fTsIndex     = UINT64_MAX;
+    uint64_t fTsStartTime = UINT64_MAX;
+
+    std::vector<CbmDigiEvent> fDigiEvents;
+
+    friend class boost::serialization::access;
+
+    template<class Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+      ar& fTsIndex;
+      ar& fTsStartTime;
+
+      ar& fDigiEvents;
+    }
+  };
+
+}  // namespace cbm::algo
+
+#endif  // CBM_ALGO_GLOBAL_STORABLE_RECO_RESULTS_H
diff --git a/external/InstallFlesnet.cmake b/external/InstallFlesnet.cmake
index b2bb9d9bdc9092c5e96da91fd7783d02b9c3607f..9368decd407c15f6e37142d285ca9d3b1299eeba 100644
--- a/external/InstallFlesnet.cmake
+++ b/external/InstallFlesnet.cmake
@@ -3,7 +3,7 @@
 # The included libraries provide the interface to the experiment data in timeslices
 # both online and in timeslice archive (.tsa) files.
 
-set(FLESNET_VERSION 8a8b7cefd37b18cfd15a3c0c812ff652217e994e) # 2023-07-06
+set(FLESNET_VERSION 0529b038b2c2c8d9b82580e0d080a6abc2ef199f) # 2023-07-18
 
 set(FLESNET_SRC_URL "https://github.com/cbm-fles/flesnet")
 
diff --git a/reco/app/cbmreco/main.cxx b/reco/app/cbmreco/main.cxx
index 361e2f5d9965cf95d0beb4da13f86093f7a6d027..e1f2dd99800e13ba675fb9a6ace3fc5ac6863c49 100644
--- a/reco/app/cbmreco/main.cxx
+++ b/reco/app/cbmreco/main.cxx
@@ -10,14 +10,63 @@
 
 #include <xpu/host.h>
 
-#include "Archive.h"
 #include "BuildInfo.h"
 #include "Options.h"
 #include "Reco.h"
+#include "RecoResultsInputArchive.h"
+#include "RecoResultsOutputArchive.h"
 #include "compat/OpenMP.h"
 
 using namespace cbm::algo;
 
+std::shared_ptr<StorableRecoResults> makeStorableRecoResults(const fles::Timeslice& ts, const RecoResults& results)
+{
+  auto storable = std::make_shared<StorableRecoResults>(ts.index(), ts.start_time());
+  storable->DigiEvents().reserve(results.events.size());
+  for (const auto& digiEvent : results.events) {
+    storable->DigiEvents().emplace_back(digiEvent.ToStorable());
+  }
+  return storable;
+}
+
+bool dumpArchive(const Options& opts)
+{
+  // Limit the number of events per timeslice to dump to avoid spamming the log
+  constexpr size_t DumpEventsPerTS = 10;
+
+  if (!opts.DumpArchive()) return false;
+
+  L_(info) << "Dumping archive: " << opts.InputLocator();
+
+  RecoResultsInputArchive archive(opts.InputLocator());
+
+  auto desc = archive.descriptor();
+  L_(info) << "Archive descriptor: ";
+  L_(info) << " - time_created: " << desc.time_created();
+  L_(info) << " - hostname: " << desc.hostname();
+  L_(info) << " - username: " << desc.username();
+
+  for (auto recoResults = archive.get(); !archive.eos(); recoResults = archive.get()) {
+    if (recoResults == nullptr) {
+      L_(error) << "Failed to read RecoResults from archive";
+      break;
+    }
+
+    size_t nEvents = recoResults->DigiEvents().size();
+    L_(info) << "TS " << recoResults->TsIndex() << " start: " << recoResults->TsStartTime() << " events: " << nEvents;
+
+    for (size_t i = 0; i < std::min(DumpEventsPerTS, nEvents); i++) {
+      const auto& digiEvent = recoResults->DigiEvents().at(i);
+      L_(info) << " - Event " << i << " number: " << digiEvent.fNumber << "; time: " << digiEvent.fTime
+               << "; nStsDigis: " << digiEvent.fData.Size(ECbmModuleId::kSts);
+    }
+
+    if (nEvents > DumpEventsPerTS) L_(info) << "...";
+  }
+
+  return true;
+}
+
 int main(int argc, char** argv)
 {
   Options opts {argc, argv};
@@ -52,11 +101,19 @@ int main(int argc, char** argv)
   }
   L_(info) << ss.str();
 
+  if (dumpArchive(opts)) return 0;
+
   Reco reco;
   reco.Init(opts);
 
-  Archive archive(ArchiveDescriptor {});  // TODO: use opts.Detector() once detector flag is merged
   fles::TimesliceAutoSource source {opts.InputLocator()};
+
+  std::optional<RecoResultsOutputArchive> archive;
+  if (!opts.OutputFile().empty()) {
+    L_(info) << "Writing results to file: " << opts.OutputFile();
+    archive.emplace(opts.OutputFile().string());
+  }
+
   int tsIdx  = 0;
   int num_ts = opts.NumTimeslices();
   if (num_ts > 0) { num_ts += opts.SkipTimeslices(); }
@@ -67,24 +124,17 @@ int main(int argc, char** argv)
     }
     auto result = reco.Run(*ts);
 
-    if (opts.SplitOutputPerTS() && !opts.OutputFile().empty()) {
-      Archive tsResults(ArchiveDescriptor {});  // TODO: use opts.Detector() once detector flag is merged
-      for (auto& event : result.events) {
-        tsResults.TimesliceResults().emplace_back(event.ToStorable());
-      }
-      tsResults.Store(opts.OutputFile(), ts->index());
-    }
-    else {
-      for (auto& event : result.events) {
-        archive.TimesliceResults().emplace_back(event.ToStorable());
-      }
+    if (archive) {
+      auto storable = makeStorableRecoResults(*ts, result);
+      archive->put(storable);
     }
     tsIdx++;
 
     if (num_ts > 0 && tsIdx >= num_ts) { break; }
   }
 
-  if (!opts.SplitOutputPerTS() && !opts.OutputFile().empty()) archive.Store(opts.OutputFile());
+  if (archive) archive->end_stream();
+
   reco.Finalize();
 
   return 0;