diff --git a/corsika/detail/framework/core/Cascade.inl b/corsika/detail/framework/core/Cascade.inl
index 07ec495469d8b1ef64f896f2b6facb3853ed60c0..64ca0a3aa5ff2f9fb0a95062d27ba4dcdba4807c 100644
--- a/corsika/detail/framework/core/Cascade.inl
+++ b/corsika/detail/framework/core/Cascade.inl
@@ -31,10 +31,12 @@ namespace corsika {
     setNodes(); // put each particle on stack in correct environment volume
 
     while (!stack_.isEmpty()) {
+
+      sequence_.initCascadeEquations();
+
       while (!stack_.isEmpty()) {
         CORSIKA_LOG_TRACE("Stack: {}", stack_.asString());
         count_++;
-
         auto pNext = stack_.getNextParticle();
 
         CORSIKA_LOG_TRACE(
@@ -46,9 +48,10 @@ namespace corsika {
         step(pNext);
         sequence_.doStack(stack_);
       }
+
       // do cascade equations, which can put new particles on Stack,
       // thus, the double loop
-      // doCascadeEquations();
+      sequence_.doCascadeEquations(stack_);
     }
   }
 
diff --git a/corsika/detail/framework/process/CascadeEquationsProcess.hpp b/corsika/detail/framework/process/CascadeEquationsProcess.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..94e973c7888b15e1d68c209a2a0369cdd387618b
--- /dev/null
+++ b/corsika/detail/framework/process/CascadeEquationsProcess.hpp
@@ -0,0 +1,60 @@
+/*
+ * (c) Copyright 2021 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/framework/process/ProcessTraits.hpp>
+#include <corsika/framework/utility/HasMethodSignature.hpp>
+
+/**
+ * @file CascadeEquationsProcess.hpp
+ */
+
+namespace corsika {
+
+  /**
+   * traits test for CascadeEquationsProcess::doCascadeEquations method.
+   */
+  template <class TProcess, typename TReturn, typename... TArg>
+  struct has_method_doCascadeEquations
+      : public detail::has_method_signature<TReturn, TArg...> {
+
+    //! method signature
+    using detail::has_method_signature<TReturn, TArg...>::testSignature;
+
+    //! the default value
+    template <class T>
+    static std::false_type test(...);
+
+    //! templated parameter option
+    template <class T>
+    static decltype(testSignature(&T::template doCascadeEquations<TArg...>)) test(
+        std::nullptr_t);
+
+    //! non templated parameter option
+    template <class T>
+    static decltype(testSignature(&T::doCascadeEquations)) test(std::nullptr_t);
+
+  public:
+    /**
+     *  @name traits results
+     *  @{
+     */
+    using type = decltype(test<std::decay_t<TProcess>>(nullptr));
+    static const bool value = type::value;
+    //! @}
+  };
+
+  /**
+   * value traits type.
+   */
+  template <class TProcess, typename TReturn, typename... TArg>
+  bool constexpr has_method_doCascadeEquations_v =
+      has_method_doCascadeEquations<TProcess, TReturn, TArg...>::value;
+
+} // namespace corsika
diff --git a/corsika/detail/framework/process/ProcessSequence.inl b/corsika/detail/framework/process/ProcessSequence.inl
index 5eb3d20ae785b7645101b362cb4697282a29ecdd..4d381abb16af98729d6defdfb53bfc0503d420f9 100644
--- a/corsika/detail/framework/process/ProcessSequence.inl
+++ b/corsika/detail/framework/process/ProcessSequence.inl
@@ -19,6 +19,7 @@
 #include <corsika/framework/process/ProcessReturn.hpp>
 #include <corsika/framework/process/SecondariesProcess.hpp>
 #include <corsika/framework/process/StackProcess.hpp>
+#include <corsika/framework/process/CascadeEquationsProcess.hpp>
 
 #include <cmath>
 #include <limits>
@@ -331,6 +332,79 @@ namespace corsika {
     return tot;
   }
 
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
+  template <typename TStack>
+  void ProcessSequence<TProcess1, TProcess2, IndexStart, IndexProcess1,
+                       IndexProcess2>::doCascadeEquations(TStack& stack) {
+
+    if constexpr (is_process_v<process1_type>) { // to protect from further compiler
+                                                 // errors if process1_type is invalid
+      if constexpr (process1_type::is_process_sequence &&
+                    !process1_type::is_switch_process_sequence) {
+
+        A_.doCascadeEquations(stack);
+
+      } else if constexpr (is_cascade_equations_process_v<process1_type>) {
+
+        // interface checking on TProcess1
+        static_assert(has_method_doCascadeEquations_v<TProcess1,
+                                                      void,     // return type
+                                                      TStack&>, // parameter
+                      "TDerived has no method with correct signature \"void "
+                      "doCascadeEquations(TStack&)\" required for "
+                      "CascadeEquationsProcess<TDerived>. ");
+
+        A_.doCascadeEquations(stack);
+      }
+    }
+
+    if constexpr (is_process_v<process2_type>) { // to protect from further compiler
+                                                 // errors if process2_type is invalid
+      if constexpr (process2_type::is_process_sequence &&
+                    !process2_type::is_switch_process_sequence) {
+
+        B_.doCascadeEquations(stack);
+
+      } else if constexpr (is_cascade_equations_process_v<process2_type>) {
+
+        // interface checking on TProcess2
+        static_assert(has_method_doCascadeEquations_v<TProcess2,
+                                                      void,     // return type
+                                                      TStack&>, // parameter
+                      "TDerived has no method with correct signature \"void "
+                      "doCascadeEquations(TStack&)\" required for "
+                      "CascadeEquationsProcess<TDerived>. ");
+
+        B_.doCascadeEquations(stack);
+      }
+    }
+  }
+
+  template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
+            int IndexProcess2>
+  void ProcessSequence<TProcess1, TProcess2, IndexStart, IndexProcess1,
+                       IndexProcess2>::initCascadeEquations() {
+
+    if constexpr (is_process_v<process1_type>) { // to protect from further compiler
+                                                 // errors if process1_type is invalid
+      if constexpr ((process1_type::is_process_sequence &&
+                     !process1_type::is_switch_process_sequence) ||
+                    is_cascade_equations_process_v<process1_type>) {
+        A_.initCascadeEquations();
+      }
+    }
+
+    if constexpr (is_process_v<process2_type>) { // to protect from further compiler
+                                                 // errors if process2_type is invalid
+      if constexpr ((process2_type::is_process_sequence &&
+                     !process2_type::is_switch_process_sequence) ||
+                    is_cascade_equations_process_v<process2_type>) {
+        B_.initCascadeEquations();
+      }
+    }
+  } // namespace corsika
+
   template <typename TProcess1, typename TProcess2, int IndexStart, int IndexProcess1,
             int IndexProcess2>
   template <typename TSecondaryView>
@@ -485,8 +559,8 @@ namespace corsika {
   }
 
   /**
-   * traits marker to identify objects containing any StackProcesses
-   **/
+   * traits marker to identify objects containing any StackProcesses.
+   */
   namespace detail {
     // need helper alias to achieve this:
     template <
diff --git a/corsika/detail/framework/process/SecondariesProcess.hpp b/corsika/detail/framework/process/SecondariesProcess.hpp
index ee76cce853d29f7007d9a82ed88b12e0826a31f6..f0055581466dcfd0cfa60f040fe2323e4fefe51a 100644
--- a/corsika/detail/framework/process/SecondariesProcess.hpp
+++ b/corsika/detail/framework/process/SecondariesProcess.hpp
@@ -14,8 +14,8 @@
 namespace corsika {
 
   /**
-     traits test for SecondariesProcess::doSecondaries method
-  */
+   * traits test for SecondariesProcess::doSecondaries method.
+   */
   template <class TProcess, typename TReturn, typename... TArg>
   struct has_method_doSecondaries
       : public detail::has_method_signature<TReturn, TArg...> {
@@ -38,16 +38,19 @@ namespace corsika {
 
   public:
     /**
-        @name traits results
-        @{
-    */
+     *  @name traits results
+     *  @{
+     */
     using type = decltype(test<std::decay_t<TProcess>>(nullptr));
     static const bool value = type::value;
     //! @}
   };
 
-  //! @file DecayProcess.hpp
-  //! value traits type
+  /**
+   * @file SecondariesProcess.hpp
+   *
+   * @brief value traits type.
+   */
   template <class TProcess, typename TReturn, typename... TArg>
   bool constexpr has_method_doSecondaries_v =
       has_method_doSecondaries<TProcess, TReturn, TArg...>::value;
diff --git a/corsika/detail/modules/StackInspector.inl b/corsika/detail/modules/StackInspector.inl
index 24a356fcb749f90796db5920bef351dee2d10ac9..06705ac8f6be0892750e8c3942e4710d273b6dc8 100644
--- a/corsika/detail/modules/StackInspector.inl
+++ b/corsika/detail/modules/StackInspector.inl
@@ -61,28 +61,44 @@ namespace corsika {
     if (dE < dE_threshold_) return;
     double const progress = dE / E0_;
 
-    double const eta_seconds = elapsed_seconds.count() / progress;
     std::time_t const start_time = std::chrono::system_clock::to_time_t(StartTime_);
-    std::time_t const eta_time = std::chrono::system_clock::to_time_t(
-        StartTime_ + std::chrono::seconds((int)eta_seconds));
-
-    int const yday0 = std::localtime(&start_time)->tm_yday;
-    int const yday1 = std::localtime(&eta_time)->tm_yday;
-    int const dyday = yday1 - yday0;
-
-    CORSIKA_LOG_INFO(
-        "StackInspector: "
-        " time={}"
-        ", running={} seconds"
-        " ( {:.1f}%)"
-        ", nStep={}"
-        ", stackSize={}"
-        ", Estack={} GeV"
-        ", ETA={}{}",
-        std::put_time(std::localtime(&now_time), "%T"), elapsed_seconds.count(),
-        (progress * 100), getStep(), vS.getSize(), Etot / 1_GeV,
-        (dyday == 0 ? "" : fmt::format("+{}d ", dyday)),
-        std::put_time(std::localtime(&eta_time), "%T"));
+
+    if (progress > 0) {
+
+      double const eta_seconds = elapsed_seconds.count() / progress;
+      std::time_t const eta_time = std::chrono::system_clock::to_time_t(
+          StartTime_ + std::chrono::seconds((int)eta_seconds));
+
+      int const yday0 = std::localtime(&start_time)->tm_yday;
+      int const yday1 = std::localtime(&eta_time)->tm_yday;
+      int const dyday = yday1 - yday0;
+
+      CORSIKA_LOG_INFO(
+          "StackInspector: "
+          " time={}"
+          ", running={} seconds"
+          " ( {:.1f}%)"
+          ", nStep={}"
+          ", stackSize={}"
+          ", Estack={} GeV"
+          ", ETA={}{}",
+          std::put_time(std::localtime(&now_time), "%T"), elapsed_seconds.count(),
+          (progress * 100), getStep(), vS.getSize(), Etot / 1_GeV,
+          (dyday == 0 ? "" : fmt::format("+{}d ", dyday)),
+          std::put_time(std::localtime(&eta_time), "%T"));
+    } else {
+      CORSIKA_LOG_INFO(
+          "StackInspector: "
+          " time={}"
+          ", running={} seconds"
+          " ( {:.1f}%)"
+          ", nStep={}"
+          ", stackSize={}"
+          ", Estack={} GeV"
+          ", ETA={}{}",
+          std::put_time(std::localtime(&now_time), "%T"), elapsed_seconds.count(),
+          (progress * 100), getStep(), vS.getSize(), Etot / 1_GeV, "---", "---");
+    }
   }
 
 } // namespace corsika
diff --git a/corsika/detail/modules/conex/CONEXhybrid.inl b/corsika/detail/modules/conex/CONEXhybrid.inl
index 3a8109f631d41275567bda02e713e3d47b404a8f..00e79005e236ef415bbdc5174d0615dec90f5049 100644
--- a/corsika/detail/modules/conex/CONEXhybrid.inl
+++ b/corsika/detail/modules/conex/CONEXhybrid.inl
@@ -28,6 +28,9 @@ namespace corsika {
       : center_{center}
       , showerAxis_{showerAxis}
       , groundDist_{groundDist}
+      , injectionHeight_{injectionHeight}
+      , primaryEnergy_{primaryEnergy}
+      , primaryPDG_{primaryPDG}
       , showerCore_{showerAxis_.getStart() + showerAxis_.getDirection() * groundDist_}
       , conexObservationCS_{std::invoke([&]() {
         auto const& c8cs = center.getCoordinateSystem();
@@ -77,7 +80,9 @@ namespace corsika {
     CORSIKA_LOG_DEBUG("showerCore (C8): {}",
                       showerCore_.getCoordinates(center.getCoordinateSystem()));
 
-    int randomSeeds[3] = {1234, 0, 0}; // will be overwritten later??
+    int randomSeeds[3] = {1234, 0,
+                          0}; // SEEDS ARE NOT USED. All random numbers are obtained from
+                              // the CORSIKA 8 stream "conex" and "epos"!
     int heModel = eSibyll23;
 
     int nShower = 1; // large to avoid final stats.
@@ -92,8 +97,9 @@ namespace corsika {
                         particleListMode,
 #endif
                         configPath.c_str(), configPath.size());
+  }
 
-    double eprima = primaryEnergy / 1_GeV;
+  inline void CONEXhybrid::initCascadeEquations() {
 
     // set phi, theta
     Vector<length_d> ez{conexObservationCS_, {0._m, 0._m, -1_m}};
@@ -111,16 +117,17 @@ namespace corsika {
         "; phi (deg) = {}",
         theta, phi);
 
-    int ipart = static_cast<int>(primaryPDG);
-    auto rng = RNGManager<>::getInstance().getRandomStream("conex");
+    int ipart = static_cast<int>(primaryPDG_);
 
     double dimpact = 0.; // valid only if shower core is fixed on the observation plane;
                          // for skimming showers an offset is needed like in CONEX
 
-    std::array<int, 3> ioseed{static_cast<int>(rng()), static_cast<int>(rng()),
-                              static_cast<int>(rng())};
+    // SEEDS ARE NOT USED. All random numbers are obtained from
+    // the CORSIKA 8 stream "conex" and "epos"!
+    std::array<int, 3> ioseed{1, 1, 1};
 
-    double xminp = injectionHeight / 1_m;
+    double eprima = primaryEnergy_ / 1_GeV;
+    double xminp = injectionHeight_ / 1_m;
 
     ::conex::conexrun_(ipart, eprima, theta, phi, xminp, dimpact, ioseed.data());
   }
@@ -225,7 +232,8 @@ namespace corsika {
     return true;
   }
 
-  inline void CONEXhybrid::solveCE() {
+  template <typename TStack>
+  inline void CONEXhybrid::doCascadeEquations(TStack&) {
 
     ::conex::conexcascade_();
 
diff --git a/corsika/detail/modules/sibyll/Interaction.inl b/corsika/detail/modules/sibyll/Interaction.inl
index e4fdeec751684a0f143fbcc4420a51132bea5cf4..ed42473ec865d339e540e7b7e1904df763136e09 100644
--- a/corsika/detail/modules/sibyll/Interaction.inl
+++ b/corsika/detail/modules/sibyll/Interaction.inl
@@ -206,10 +206,8 @@ namespace corsika::sibyll {
     // just for show:
     // boost projecticle
     [[maybe_unused]] auto const PprojCoM = boost.toCoM(PprojLab);
-
     // boost target
     [[maybe_unused]] auto const PtargCoM = boost.toCoM(PtargLab);
-
     CORSIKA_LOG_DEBUG(
         "Interaction: ebeam CoM: {} GeV "
         "Interaction: pbeam CoM: {} GeV ",
@@ -328,15 +326,16 @@ namespace corsika::sibyll {
         Ecm_final += psib.getEnergy();
       }
       CORSIKA_LOG_DEBUG(
-          "conservation (all GeV):"
-          "Ecm_initial(per nucleon)={}, Ecm_final(per nucleon)={}, "
-          "Elab_initial={}, Elab_final={}, "
-          "diff (%)={}, "
-          "E in nucleons={}, "
-          "Plab_initial={}, "
-          "Plab_final={} ",
+          "conservation (all GeV): "
+          "Ecm_initial(per nucleon)={:.2f}, Ecm_final(per nucleon)={:.2f}, "
+          "Elab_initial={:.2f}, Elab_final={:.2f}, "
+          "Elab-diff (%)={:.2f}, "
+          "m in target nucleons={:.2f}, "
+          "Plab_initial={:.2f}, "
+          "Plab_final={:.2f} ",
           Ecm / 1_GeV, Ecm_final * 2. / (get_nwounded() + 1) / 1_GeV, Etot / 1_GeV,
-          Elab_final / 1_GeV, (Elab_final / Etot / get_nwounded() - 1) * 100,
+          Elab_final / 1_GeV,
+          (Elab_final / (Etot + get_nwounded() * constants::nucleonMass) - 1) * 100,
           constants::nucleonMass * get_nwounded() / 1_GeV,
           (pProjectileLab / 1_GeV).getComponents(), (Plab_final / 1_GeV).getComponents());
     }
diff --git a/corsika/detail/modules/tracking/Intersect.inl b/corsika/detail/modules/tracking/Intersect.inl
index 6888f09a0607673cb82ae87d58a5ed6c67db11ce..b81cbf5c2eca1202f8ee7bb05aaf9f292424b854 100644
--- a/corsika/detail/modules/tracking/Intersect.inl
+++ b/corsika/detail/modules/tracking/Intersect.inl
@@ -60,7 +60,8 @@ namespace corsika {
     for (auto const& node : volumeNode.getChildNodes()) {
 
       Intersections const time_intersections = TDerived::intersect(particle, *node);
-      CORSIKA_LOG_DEBUG("intersection times with child volume {}", fmt::ptr(node));
+      CORSIKA_LOG_DEBUG("search intersection times with child volume {}:",
+                        fmt::ptr(node));
       if (!time_intersections.hasIntersections()) { continue; }
       auto const t_entry = time_intersections.getEntry();
       auto const t_exit = time_intersections.getExit();
diff --git a/corsika/framework/process/CascadeEquationsProcess.hpp b/corsika/framework/process/CascadeEquationsProcess.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5e92389f6be3d99e62e705559eabc31e5a50e648
--- /dev/null
+++ b/corsika/framework/process/CascadeEquationsProcess.hpp
@@ -0,0 +1,55 @@
+/*
+ * (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#pragma once
+
+#include <corsika/framework/process/BaseProcess.hpp>
+#include <corsika/framework/core/PhysicalUnits.hpp>
+
+#include <corsika/detail/framework/process/CascadeEquationsProcess.hpp> // for extra traits, method/interface checking
+
+namespace corsika {
+
+  /**
+   * @ingroup Processes
+   * @{
+   *
+   * Processes executing cascade-equations calculations.
+   *
+   * Create a new CascadeEquationsProcess, e.g. for XYModel, via:
+   * @code{.cpp}
+   * class XYModel : public CascadeEquationsProcess<XYModel> {};
+   * @endcode
+   *
+   * and provide the necessary interface method:
+   * @code{.cpp}
+   * template <typename TStack>
+   * void doCascadeEquations(TStack& stack);
+   * @endcode
+   *
+   * Cascade equation processes may generate new particles on the stack. They also
+   * typically generate output.
+   */
+
+  template <typename TDerived>
+  class CascadeEquationsProcess : public BaseProcess<TDerived> {
+  public:
+  };
+
+  /**
+   * ProcessTraits specialization to flag CascadeEquationsProcess objects.
+   */
+  template <typename TProcess>
+  struct is_cascade_equations_process<
+      TProcess, std::enable_if_t<std::is_base_of_v<
+                    CascadeEquationsProcess<typename std::decay_t<TProcess>>,
+                    typename std::decay_t<TProcess>>>> : std::true_type {};
+
+  //! @}
+
+} // namespace corsika
diff --git a/corsika/framework/process/ProcessSequence.hpp b/corsika/framework/process/ProcessSequence.hpp
index 05191c248d5e1b17ceb5cfe39fc5dfe2fcabe4f6..407f403495c7c4d281880a897366f3b76b22a123 100644
--- a/corsika/framework/process/ProcessSequence.hpp
+++ b/corsika/framework/process/ProcessSequence.hpp
@@ -20,6 +20,7 @@
 #include <corsika/framework/process/ContinuousProcessStepLength.hpp>
 #include <corsika/framework/process/DecayProcess.hpp>
 #include <corsika/framework/process/InteractionProcess.hpp>
+#include <corsika/framework/process/CascadeEquationsProcess.hpp>
 #include <corsika/framework/process/ProcessReturn.hpp>
 #include <corsika/framework/process/SecondariesProcess.hpp>
 #include <corsika/framework/process/StackProcess.hpp>
@@ -209,6 +210,17 @@ namespace corsika {
     template <typename TStack>
     void doStack(TStack& stack);
 
+    /**
+     * Execute the CascadeEquationsProcess-es in the ProcessSequence.
+     */
+    template <typename TStack>
+    void doCascadeEquations(TStack& stack);
+
+    /**
+     * Init the CascadeEquationsProcess-es in the ProcessSequence.
+     */
+    void initCascadeEquations();
+
     /**
      * Calculate the maximum allowed length of the next tracking step, based on all
      * ContinuousProcess-es
diff --git a/corsika/framework/process/ProcessTraits.hpp b/corsika/framework/process/ProcessTraits.hpp
index cccd80abaf1a11436befc913eaaf785112c5b123..24910fece0f821a7ac21b4e271ac0bb2c72f8140 100644
--- a/corsika/framework/process/ProcessTraits.hpp
+++ b/corsika/framework/process/ProcessTraits.hpp
@@ -17,7 +17,7 @@
 namespace corsika {
 
   /**
-   * A traits marker to identify BaseProcess, thus any type of process
+   * A traits marker to identify BaseProcess, thus any type of process.
    */
   template <typename TProcess, typename TEnable = void>
   struct is_process : std::false_type {};
@@ -26,7 +26,7 @@ namespace corsika {
   bool constexpr is_process_v = is_process<TProcess>::value;
 
   /**
-   * A traits marker to identify ContinuousProcess
+   * A traits marker to identify ContinuousProcess.
    */
   template <typename TProcess, typename Enable = void>
   struct is_continuous_process : std::false_type {};
@@ -35,7 +35,7 @@ namespace corsika {
   bool constexpr is_continuous_process_v = is_continuous_process<TProcess>::value;
 
   /**
-   * A traits marker to identify DecayProcess
+   * A traits marker to identify DecayProcess.
    */
   template <typename TProcess, typename Enable = void>
   struct is_decay_process : std::false_type {};
@@ -44,7 +44,7 @@ namespace corsika {
   bool constexpr is_decay_process_v = is_decay_process<TProcess>::value;
 
   /**
-   * A traits marker to identify StackProcess
+   * A traits marker to identify StackProcess.
    */
   template <typename TProcess, typename Enable = void>
   struct is_stack_process : std::false_type {};
@@ -53,7 +53,17 @@ namespace corsika {
   bool constexpr is_stack_process_v = is_stack_process<TProcess>::value;
 
   /**
-   * A traits marker to identify SecondariesProcess
+   * A traits marker to identify CascadeEquationsProcess.
+   */
+  template <typename TProcess, typename Enable = void>
+  struct is_cascade_equations_process : std::false_type {};
+
+  template <typename TProcess>
+  bool constexpr is_cascade_equations_process_v =
+      is_cascade_equations_process<TProcess>::value;
+
+  /**
+   * A traits marker to identify SecondariesProcess.
    */
   template <typename TProcess, typename Enable = void>
   struct is_secondaries_process : std::false_type {};
@@ -62,7 +72,7 @@ namespace corsika {
   bool constexpr is_secondaries_process_v = is_secondaries_process<TProcess>::value;
 
   /**
-   * A traits marker to identify BoundaryProcess
+   * A traits marker to identify BoundaryProcess.
    */
   template <typename TProcess, typename Enable = void>
   struct is_boundary_process : std::false_type {};
@@ -71,7 +81,7 @@ namespace corsika {
   bool constexpr is_boundary_process_v = is_boundary_process<TProcess>::value;
 
   /**
-   * A traits marker to identify InteractionProcess
+   * A traits marker to identify InteractionProcess.
    */
   template <typename TProcess, typename Enable = void>
   struct is_interaction_process : std::false_type {};
@@ -80,8 +90,8 @@ namespace corsika {
   bool constexpr is_interaction_process_v = is_interaction_process<TProcess>::value;
 
   /**
-   * A traits marker to identify ProcessSequence that contain a StackProcess
-   **/
+   * A traits marker to identify ProcessSequence that contain a StackProcess.
+   */
   template <typename TClass>
   struct contains_stack_process : std::false_type {};
 
@@ -89,8 +99,8 @@ namespace corsika {
   bool constexpr contains_stack_process_v = contains_stack_process<TClass>::value;
 
   /**
-   * traits class to count any type of Process, general version
-   **/
+   * traits class to count any type of Process, general version.
+   */
   template <typename TProcess, int N = 0, typename Enable = void>
   struct count_processes {
     static unsigned int constexpr count = N;
diff --git a/corsika/framework/process/SecondariesProcess.hpp b/corsika/framework/process/SecondariesProcess.hpp
index 975b1e7851174b3be25e43a99ef06c5155a2912c..8fdc6b67d9f5e2c720b59773efcb7131fa57c886 100644
--- a/corsika/framework/process/SecondariesProcess.hpp
+++ b/corsika/framework/process/SecondariesProcess.hpp
@@ -16,24 +16,24 @@
 namespace corsika {
 
   /**
-     @ingroup Processes
-     @{
-
-     Processes acting on the secondaries produced by other processes.
-
-     Create a new SecondariesProcess, e.g. for XYModel, via
-     @code{.cpp}
-     class XYModel : public SecondariesProcess<XYModel> {};
-     @endcode
-
-     and provide the necessary interface method:
-     @code{.cpp}
-     template <typename TStackView>
-     void doSecondaries(TStackView& StackView);
-     @endcode
-
-     where StackView is an object that can store secondaries on a
-     stack and also iterate over these secondaries.
+   * @ingroup Processes
+   * @{
+   *
+   * Processes acting on the secondaries produced by other processes.
+   *
+   * Create a new SecondariesProcess, e.g. for XYModel, via
+   * @code{.cpp}
+   * class XYModel : public SecondariesProcess<XYModel> {};
+   * @endcode
+   *
+   * and provide the necessary interface method:
+   * @code{.cpp}
+   * template <typename TStackView>
+   * void doSecondaries(TStackView& StackView);
+   * @endcode
+   *
+   * where StackView is an object that can store secondaries on a
+   * stack and also iterate over these secondaries.
    */
 
   template <typename TDerived>
@@ -42,8 +42,8 @@ namespace corsika {
   };
 
   /**
-   * ProcessTraits specialization to flag SecondariesProcess objects
-   **/
+   * ProcessTraits specialization to flag SecondariesProcess objects.
+   */
   template <typename TProcess>
   struct is_secondaries_process<
       TProcess, std::enable_if_t<
diff --git a/corsika/framework/process/StackProcess.hpp b/corsika/framework/process/StackProcess.hpp
index 773265f49e102b63ca447191a25040c555179c37..34a9c50bceef5412a6b5f1b19cda29e02b03f8bd 100644
--- a/corsika/framework/process/StackProcess.hpp
+++ b/corsika/framework/process/StackProcess.hpp
@@ -16,32 +16,32 @@
 namespace corsika {
 
   /**
-     @ingroup Processes
-     @{
-
-     Process to act on the entire particle stack
-
-     Create a new StackProcess, e.g. for XYModel, via
-     @code{.cpp}
-     class XYModel : public StackProcess<XYModel> {};
-     @endcode
-
-     and provide the necessary interface method
-     @code{.cpp}
-     template <typename TStack>
-     void XYModel::doStack(TStack&);
-     @endcode
-
-     Where, of course, Stack is the valid
-     class to access particles on the Stack. This methods does
-     not need to be templated, they could use the types
-     e.g. corsika::setup::Stack directly -- but by the cost of
-     loosing all flexibility otherwise provided.
-
-     A StackProcess has only one constructor `StackProcess::StackProcess(unsigned int
-     const nStep)` where nStep is the number of steps of the cascade stepping after which
-     the stack process should be run. Good values are on the order of 1000, which will not
-     compromise run time in the end, but provide all the benefits of the StackProcess.
+   * @ingroup Processes
+   * @{
+   *
+   * Process to act on the entire particle stack.
+   *
+   * Create a new StackProcess, e.g. for XYModel, via:
+   * @code{.cpp}
+   * class XYModel : public StackProcess<XYModel> {};
+   * @endcode
+   *
+   * and provide the necessary interface method:
+   * @code{.cpp}
+   * template <typename TStack>
+   * void XYModel::doStack(TStack&);
+   * @endcode
+   *
+   * Where, of course, Stack is the valid
+   * class to access particles on the Stack. This methods does
+   * not need to be templated, they could use the types
+   * e.g. corsika::setup::Stack directly -- but by the cost of
+   * loosing all flexibility otherwise provided.
+   *
+   * A StackProcess has only one constructor `StackProcess::StackProcess(unsigned int
+   * const nStep)` where nStep is the number of steps of the cascade stepping after which
+   * the stack process should be run. Good values are on the order of 1000, which will not
+   * compromise run time in the end, but provide all the benefits of the StackProcess.
    */
 
   template <typename TDerived>
@@ -64,10 +64,10 @@ namespace corsika {
 
   private:
     /**
-       @name The number of "steps" during the cascade processing after
-       which this StackProcess is going to be executed. The logic is
-       "iStep_ modulo nStep_"
-       @{
+     * @name The number of "steps" during the cascade processing after
+     * which this StackProcess is going to be executed. The logic is
+     * "iStep_ modulo nStep_"
+     * @{
      */
     unsigned int nStep_ = 0;
     unsigned long int iStep_ = 0;
@@ -75,8 +75,8 @@ namespace corsika {
   };
 
   /**
-   * ProcessTraits specialization to flag StackProcess objects
-   **/
+   * ProcessTraits specialization to flag StackProcess objects.
+   */
   template <typename TProcess>
   struct is_stack_process<
       TProcess,
diff --git a/corsika/modules/conex/CONEXhybrid.hpp b/corsika/modules/conex/CONEXhybrid.hpp
index 2f0b80873dfa4109202f1a01cb11ff571c988cfd..0d3878e474212cab10c6fefaf81ad8b23067d145 100644
--- a/corsika/modules/conex/CONEXhybrid.hpp
+++ b/corsika/modules/conex/CONEXhybrid.hpp
@@ -8,11 +8,13 @@
 
 #pragma once
 
+#include <corsika/framework/process/SecondariesProcess.hpp>
+#include <corsika/framework/process/CascadeEquationsProcess.hpp>
+
 #include <corsika/framework/core/PhysicalUnits.hpp>
 #include <corsika/framework/core/ParticleProperties.hpp>
 #include <corsika/framework/geometry/Point.hpp>
 #include <corsika/framework/geometry/Vector.hpp>
-#include <corsika/framework/process/SecondariesProcess.hpp>
 #include <corsika/media/ShowerAxis.hpp>
 
 #include <corsika/modules/conex/CONEX_f.hpp>
@@ -23,17 +25,37 @@ namespace corsika {
     LengthType constexpr earthRadius{6371315 * meter};
   } // namespace conex
 
-  class CONEXhybrid : public SecondariesProcess<CONEXhybrid> {
+  class CONEXhybrid : public CascadeEquationsProcess<CONEXhybrid>,
+                      public SecondariesProcess<CONEXhybrid> {
 
   public:
     CONEXhybrid(Point center, ShowerAxis const& showerAxis, LengthType groundDist,
                 LengthType injectionHeight, HEPEnergyType primaryEnergy, PDGCode pdg);
 
+    /**
+     * Main entry point to pass new particle data towards CONEX. If a
+     * particles is selected for CONEX, it is removed from the CORSIKA
+     * 8 stack.
+     */
     template <typename TStackView>
     void doSecondaries(TStackView&);
 
-    void solveCE();
+    /**
+     * init currently needs to be called to initializa a new
+     * event. All tables are cleared, etc.
+     */
+    void initCascadeEquations();
+
+    /**
+     * Cascade equations are solved basoned on the data in the tables
+     */
+    template <typename TStack>
+    void doCascadeEquations(TStack& stack);
 
+    /**
+     * Internal function to fill particle data inside CONEX
+     * tables. Only e.m. particles are selected right now.
+     */
     bool addParticle(Code pid, HEPEnergyType energy, HEPEnergyType mass,
                      Point const& position, Vector<dimensionless_d> const& direction,
                      TimeType t);
@@ -51,8 +73,11 @@ namespace corsika {
 
     Point const center_; //!< center of CONEX Earth
     ShowerAxis const& showerAxis_;
-    LengthType groundDist_;  //!< length from injection point to shower core
-    Point const showerCore_; //!< shower core
+    LengthType groundDist_;       //!< length from injection point to shower core
+    LengthType injectionHeight_;  //!< starting height of primary particle
+    HEPEnergyType primaryEnergy_; //!< primary particle energy
+    PDGCode primaryPDG_;          //!< primary particle PDG
+    Point const showerCore_;      //!< shower core
     CoordinateSystemPtr const conexObservationCS_; //!< CONEX observation frame
     DirectionVector const x_sf_,
         y_sf_; //!< unit vectors of CONEX shower frame, z_sf is shower axis direction
diff --git a/corsika/modules/conex/Random.hpp b/corsika/modules/conex/Random.hpp
index a638a330857ebc2c011c82237df2dd4a1a1f08eb..9532eace8ed29d4322def04b5ad5fee64761b366 100644
--- a/corsika/modules/conex/Random.hpp
+++ b/corsika/modules/conex/Random.hpp
@@ -17,6 +17,19 @@
  * This file is an integral part of the epos interface. It must be
  * linked to the executable linked to epos exactly once
  *
+ * Note, that the fortran random numbe interface functions are all
+ * defined in the epos corsika 8 interface:
+ *
+ * ranfst, ranfgt, rmmaqd, ranfini, ranfcv, rmmard, rangen, drangen
+ *
+ * All of them use the epos_random_interface registered as "epos" stream.
+ *
+ * Thus, the fortran part of CONEX will use the "epos" CORSIKA 8 random stream,
+ * only the CONEX c++ part will use the "conex" random stream.
+ *
+ * Since EPOS and CONEX use the same fortran symbols for access to
+ * random numbers this can only be changed by renaming inside the
+ * fortran part.
  */
 
 namespace conex {
diff --git a/examples/hybrid_MC.cpp b/examples/hybrid_MC.cpp
index 04a126366a2d408e074532b447f3357aa4145bed..dabed46e9f4e598b4146eebd673cc9ad07721fd0 100644
--- a/examples/hybrid_MC.cpp
+++ b/examples/hybrid_MC.cpp
@@ -291,8 +291,6 @@ int main(int argc, char** argv) {
   cut.reset();
   eLoss.reset();
 
-  conex_model.solveCE();
-
   auto const hists = sibyllCounted.getHistogram() + sibyllNucCounted.getHistogram() +
                      urqmdCounted.getHistogram();
 
diff --git a/tests/modules/testCONEX.cpp b/tests/modules/testCONEX.cpp
index f86dd7b2d642c58278995823b9a250d27b36926c..985043d4dca501fab27359ff8be5eb557615ca8f 100644
--- a/tests/modules/testCONEX.cpp
+++ b/tests/modules/testCONEX.cpp
@@ -46,6 +46,8 @@ const std::string refDataDir = std::string(REFDATADIR); // from cmake
 template <typename T>
 using MExtraEnvirnoment = MediumPropertyModel<UniformMagneticField<T>>;
 
+struct DummyStack {};
+
 TEST_CASE("CONEXSourceCut") {
 
   logging::set_level(logging::level::info);
@@ -70,7 +72,7 @@ TEST_CASE("CONEXSourceCut") {
 
   builder.setNuclearComposition(
       {{Code::Nitrogen, Code::Oxygen},
-       {0.7847f, 1.f - 0.7847f}}); // values taken from AIRES manual, Ar removed for now
+       {0.7847, 1. - 0.7847}}); // values taken from AIRES manual, Ar removed for now
 
   builder.addExponentialLayer(1222.6562_g / (1_cm * 1_cm), 994186.38_cm, 4_km);
   builder.addExponentialLayer(1144.9069_g / (1_cm * 1_cm), 878153.55_cm, 10_km);
@@ -101,6 +103,7 @@ TEST_CASE("CONEXSourceCut") {
   [[maybe_unused]] corsika::sibyll::NuclearInteraction sibyllNuc(sibyll, env);
 
   CONEXhybrid conex(center, showerAxis, t, injectionHeight, E0, get_PDG(Code::Proton));
+  conex.initCascadeEquations();
 
   HEPEnergyType const Eem{1_PeV};
   auto const momentum = showerAxis.getDirection() * Eem;
@@ -122,7 +125,8 @@ TEST_CASE("CONEXSourceCut") {
   auto const momentumPhoton = showerAxis.getDirection() * 1_TeV;
   conex.addParticle(Code::Photon, 1_TeV, 0_eV, emPosition, momentumPhoton.normalized(),
                     0_s);
-  conex.solveCE();
+  DummyStack stack;
+  conex.doCascadeEquations(stack);
 }
 
 #include <algorithm>