diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/hlt1_tistos.py b/Hlt/Hlt2Conf/python/Hlt2Conf/hlt1_tistos.py
index 4174d8e9910cfa5b52f60fbf56294271454b4c01..a05e0965c9624646b8c2beaca3ba810e1ff4a63f 100644
--- a/Hlt/Hlt2Conf/python/Hlt2Conf/hlt1_tistos.py
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/hlt1_tistos.py
@@ -92,3 +92,52 @@ def hlt1_tis_or_tos_on_any_filter(
         name = "Hlt1TISORTOSFilter_{hash}"
 
     return ParticleFilter(data, F.FILTER(hlt1_combination), name=name)
+
+
+def hlt1_tistos_on_any_filter(
+    *, hlt1_trigger_lines, data, name=None, advanced_tistos_arguments={}
+) -> ParticleFilter:
+    tis_tos_table = get_hlt1_tistos_relations(
+        trigger_lines=hlt1_trigger_lines,
+        data=data,
+        advanced_tistos_arguments=advanced_tistos_arguments,
+    )
+
+    tis_functors = [F.IS_TIS(line, tis_tos_table) == 1 for line in hlt1_trigger_lines]
+    tis_combination = F.require_any(*tis_functors)
+    tos_functors = [F.IS_TOS(line, tis_tos_table) == 1 for line in hlt1_trigger_lines]
+    tos_combination = F.require_any(*tos_functors)
+
+    tistos_combination = F.require_all(tis_combination, tos_combination)
+
+    if not name:
+        name = "Hlt1TISTOSFilter_{hash}"
+
+    return ParticleFilter(data, F.FILTER(tistos_combination), name=name)
+
+
+def hlt1_numerator_tistos_filter(
+    *, hlt1_tis_lines, hlt1_tos_line, data, name=None, advanced_tistos_arguments={}
+) -> ParticleFilter:
+    """Function to compute numerator for TISTOS method:
+    hlt1_tos_line & (hlt1_tis_line[i] or hlt1_tis_line[j]...)
+    hlt1_tos_line expected to be one of the ht1_tis_lines"""
+    tis_tos_table = get_hlt1_tistos_relations(
+        trigger_lines=hlt1_tis_lines,
+        data=data,
+        advanced_tistos_arguments=advanced_tistos_arguments,
+    )
+
+    tistos_functors = [
+        F.require_all(
+            F.IS_TIS(line, tis_tos_table) == 1,
+            F.IS_TOS(hlt1_tos_line, tis_tos_table) == 1,
+        )
+        for line in hlt1_tis_lines
+    ]
+    combination = F.require_any(*tistos_functors)
+
+    if not name:
+        name = "Hlt1_num_TISTOSFilter_{hash}"
+
+    return ParticleFilter(data, F.FILTER(combination), name=name)
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/__init__.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/__init__.py
index 3c09ed18a9382d75cc14025ccb39403ca8d0c941..7d61c2a94481aee38ab28a801e5847f5cbd7fa4e 100644
--- a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/__init__.py
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/__init__.py
@@ -1,5 +1,5 @@
 ###############################################################################
-# (c) Copyright 2021 CERN for the benefit of the LHCb Collaboration           #
+# (c) Copyright 2021-2025 CERN for the benefit of the LHCb Collaboration      #
 #                                                                             #
 # This software is distributed under the terms of the GNU General Public      #
 # Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/calibmon.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/calibmon.py
index 8fca47b6669236d1dd786132fb9a0b7fd2d5b45f..596fbda30fc0e246cee0cb5c643064558209dbc6 100644
--- a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/calibmon.py
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/calibmon.py
@@ -1,5 +1,5 @@
 ###############################################################################
-# (c) Copyright 2024 CERN for the benefit of the LHCb Collaboration           #
+# (c) Copyright 2025 CERN for the benefit of the LHCb Collaboration           #
 #                                                                             #
 # This software is distributed under the terms of the GNU General Public      #
 # Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
@@ -70,7 +70,11 @@ from RecoConf.standard_particles import (
 from SelAlgorithms.monitoring import histogram_1d, histogram_2d, histogram_axis, monitor
 
 from Hlt2Conf.hlt1_tistos import hlt1_tos_on_any_filter
+from Hlt2Conf.lines.monitoring.calibmon_utils import _make_hist_list
 from Hlt2Conf.lines.trackeff import KSVeloLong
+from Hlt2Conf.lines.triggereff import triggereff_beauty_hlt2, triggereff_charm_hlt2
+
+# from RecoConf.hlt1_allen import make_converted_tracks
 from Hlt2Conf.probe_muons import (
     make_downstream_muons,
     make_muonut_muons,
@@ -78,8 +82,6 @@ from Hlt2Conf.probe_muons import (
     make_velomuon_muons,
 )
 
-# from RecoConf.hlt1_allen import make_converted_tracks
-
 
 def _calibmon_filters(pvs):
     rb_filters = []
@@ -101,45 +103,6 @@ def _calibmon_filters(pvs):
     return rb_filters + [odin_bb_filter, require_pvs(pvs)]
 
 
-def _make_hist_list(hist_dict, line_name):
-    # rearrange histos so that the the monitoring runs only once per input DataHandle
-    histos = {}
-    hist_list = []
-    for histname, params in hist_dict.items():
-        comb_name = params["input"].location.replace("/", "__")
-        ax = lambda xy: histogram_axis(
-            functor=params[f"variable_{xy}"],
-            label=params[f"label_{xy}"],
-            bins=params[f"bins_{xy}"],
-            range=params[f"range_{xy}"],
-        )
-        if "variable_x" in params:
-            hist = histogram_2d(
-                name=f"/{line_name}/{histname}",
-                title=line_name,
-                xaxis=ax("x"),
-                yaxis=ax("y"),
-            )
-        else:
-            hist = histogram_1d(
-                functor=params["variable"],
-                name=f"/{line_name}/{histname}",
-                label=params["label"],
-                bins=params["bins"],
-                range=params["range"],
-                title=line_name,
-            )
-        if comb_name in histos.keys():
-            histos[comb_name]["histograms"].append(hist)
-        else:
-            histos[comb_name] = dict(histograms=[hist], data_handle=params["input"])
-    for params in histos.values():
-        hist_list.append(
-            monitor(data=params["data_handle"], histograms=params["histograms"])
-        )
-    return hist_list
-
-
 # define a few shortcuts to make the code better readable
 def _CHILDMASS(i=1):
     return F.CHILD(i, F.MASS)
@@ -194,6 +157,8 @@ def _HLT1_DEC(lines):
 
 
 all_lines = {}
+all_lines.update(triggereff_beauty_hlt2.all_lines)
+all_lines.update(triggereff_charm_hlt2.all_lines)
 
 
 @register_line_builder(all_lines)
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/calibmon_utils.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/calibmon_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b7c561a1739aba0164285755319053dc5df7dad
--- /dev/null
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/monitoring/calibmon_utils.py
@@ -0,0 +1,50 @@
+###############################################################################
+# (c) Copyright 2025 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+from SelAlgorithms.monitoring import histogram_1d, histogram_2d, histogram_axis, monitor
+
+
+def _make_hist_list(hist_dict, line_name):
+    # rearrange histos so that the the monitoring runs only once per input DataHandle
+    histos = {}
+    hist_list = []
+    for histname, params in hist_dict.items():
+        comb_name = params["input"].location.replace("/", "__")
+        ax = lambda xy: histogram_axis(
+            functor=params[f"variable_{xy}"],
+            label=params[f"label_{xy}"],
+            bins=params[f"bins_{xy}"],
+            range=params[f"range_{xy}"],
+        )
+        if "variable_x" in params:
+            hist = histogram_2d(
+                name=f"/{line_name}/{histname}",
+                title=line_name,
+                xaxis=ax("x"),
+                yaxis=ax("y"),
+            )
+        else:
+            hist = histogram_1d(
+                functor=params["variable"],
+                name=f"/{line_name}/{histname}",
+                label=params["label"],
+                bins=params["bins"],
+                range=params["range"],
+                title=line_name,
+            )
+        if comb_name in histos.keys():
+            histos[comb_name]["histograms"].append(hist)
+        else:
+            histos[comb_name] = dict(histograms=[hist], data_handle=params["input"])
+    for params in histos.values():
+        hist_list.append(
+            monitor(data=params["data_handle"], histograms=params["histograms"])
+        )
+    return hist_list
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/__init__.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..b80112219f9d1bcb319a42555802e952fc42a63e
--- /dev/null
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/__init__.py
@@ -0,0 +1,19 @@
+###############################################################################
+# (c) Copyright 2025 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+"""
+Submodule that defines all the Trigger efficiency HLT2 lines
+"""
+
+from . import triggereff_beauty_hlt2, triggereff_charm_hlt2
+
+all_lines = {}
+all_lines.update(triggereff_beauty_hlt2.all_lines)
+all_lines.update(triggereff_charm_hlt2.all_lines)
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/monitoring_function.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/monitoring_function.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b84ac4acee7f34a03e925a39d78e2c2f1f88d66
--- /dev/null
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/monitoring_function.py
@@ -0,0 +1,87 @@
+###############################################################################
+# (c) Copyright 2025 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+import Functors as F
+from Functors.math import in_range
+
+from Hlt2Conf.lines.monitoring.calibmon_utils import _make_hist_list
+
+
+def monitoring(input_particle, particles_dictionary, line_name):
+    """
+    Function to create the histogram list for monitoring of
+    triggereff HLT2 lines with the TISTOS method
+
+    - input_particle: Particle without any TISTOS filters
+    - particles_dictionary: Dictiornary containing the input_particle
+        with the following filters:
+            - hlt1_numerator_tistos_filter for TrackMVA
+            - hlt1_numerator_tistos_filter for TwoTrackMVA
+            - hlt1_tis_on_any_filter
+            - hlt1_tistos_on_any_filter
+    - line_name: Name of the HLT2 line
+    """
+
+    mass_range = (1000, 2500)
+    eta_range = (1.5, 5.5)
+    pt_range = (0, 30 * 1e3)
+    mass_label = "m [MeV]"
+
+    hist_dict = {}
+    mass_part_dict = {
+        "bins": 50,
+    }
+    hist_dict["m"] = dict(
+        mass_part_dict,
+        input=input_particle,
+        variable=F.MASS,
+        range=mass_range,
+        label=mass_label,
+    )
+    hist_dict["pt"] = dict(
+        mass_part_dict,
+        input=input_particle,
+        variable=F.PT,
+        range=pt_range,
+        label="pt [MeV]",
+    )
+    hist_dict["eta"] = dict(
+        mass_part_dict,
+        input=input_particle,
+        variable=F.ETA,
+        range=(0, 1000000),
+        label="eta",
+    )
+
+    pt_bins = [0, 5e3, 10e3, 15e3, 20e3, 25e3]
+    eta_bins = [2.0, 3.0, 4.0, 5.0]
+    for hist_name, hist_input in particles_dictionary.items():
+        for i in range(0, len(pt_bins) - 1):
+            min_pt, max_pt = pt_bins[i], pt_bins[i + 1]
+            hist_dict[f"{hist_name}_pt_{min_pt}_{max_pt}"] = dict(
+                bins=1,
+                input=hist_input,
+                variable=F.MASS * F.POD(in_range(min_pt, F.PT, max_pt)),
+                range=mass_range,
+                label=mass_label,
+            )
+        for i in range(0, len(eta_bins) - 1):
+            min_eta, max_eta = eta_bins[i], eta_bins[i + 1]
+            hist_dict[f"{hist_name}_eta_{min_eta}_{max_eta}"] = dict(
+                bins=1,
+                input=hist_input,
+                variable=F.MASS * F.POD(in_range(min_eta, F.ETA, max_eta)),
+                range=eta_range,
+                label="eta",
+            )
+
+    hist_list = _make_hist_list(hist_dict, line_name)
+
+    return hist_list
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/triggereff_beauty_hlt2.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/triggereff_beauty_hlt2.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad5283cac19c327f1473cb6acb7a30cf0e79e9dc
--- /dev/null
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/triggereff_beauty_hlt2.py
@@ -0,0 +1,231 @@
+###############################################################################
+# (c) Copyright 2025 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+import Functors as F
+from Functors import require_all
+from Functors.math import in_range
+from GaudiKernel.SystemOfUnits import GeV, MeV, picosecond
+from Moore.config import register_line_builder
+from Moore.lines import Hlt2Line
+from RecoConf.algorithms_thor import ParticleCombiner, ParticleFilter
+from RecoConf.event_filters import require_pvs
+from RecoConf.reconstruction_objects import make_pvs, upfront_reconstruction
+from RecoConf.standard_particles import (
+    make_has_rich_long_kaons,
+    make_ismuon_long_muon,
+    make_long_kaons,
+    make_long_muons,
+)
+
+from Hlt2Conf.hlt1_tistos import (
+    hlt1_numerator_tistos_filter,
+    hlt1_tis_on_any_filter,
+    hlt1_tistos_on_any_filter,
+)
+
+from . import monitoring_function
+
+all_lines = {}
+
+
+def prefilter():
+    return upfront_reconstruction() + [require_pvs(make_pvs())]
+
+
+# make_BuToJpsimumuKplus_detached_line
+@register_line_builder(all_lines)
+def Hlt2TriggerEff_BuToJpsiKplus_JpsiToMuMu_B2CC_line(
+    process="hlt2", name="Hlt2TriggerEff_BuToJpsiKplus_JpsiToMuMu_B2CC"
+):
+    assert process in ["hlt2", "spruce"], (
+        "Line must be defined as Hlt2 or Sprucing line!"
+    )
+
+    # Build muons
+    muons_filter = require_all(
+        F.PT > 500.0 * MeV,
+        F.P > 0 * MeV,
+        F.MINIPCHI2(make_pvs()) > 0,
+        F.PID_MU > -5,
+        F.ISMUON,
+        F.ETA < 5.0,
+    )
+    muons = ParticleFilter(make_ismuon_long_muon(), F.FILTER(muons_filter))
+
+    # Build jpsi
+    combination_jpsi = require_all(
+        in_range(2700.0 * MeV, F.MASS, 3400.0 * MeV),
+        F.MAXSDOCACHI2CUT(20.0),
+        F.SUM(F.PT) > 0.0 * MeV,
+    )
+    vertex_jpsi = require_all(
+        F.PT > 500.0 * MeV, F.CHI2 < 16.0, in_range(2950.0 * MeV, F.MASS, 3250.0 * MeV)
+    )
+
+    jpsi = ParticleCombiner(
+        [muons, muons],
+        DecayDescriptor="J/psi(1S) -> mu+ mu-",
+        CombinationCut=combination_jpsi,
+        CompositeCut=vertex_jpsi,
+    )
+
+    # Build kaons
+    filter_kaons = (
+        require_all(F.PT > 800 * MeV, F.P > 3000 * MeV)
+        & (F.MINIPCHI2(make_pvs()) > 0)
+        & (F.PID_K > -1)
+    )
+    kplus = ParticleFilter(make_has_rich_long_kaons(), F.FILTER(filter_kaons))
+
+    # Build B+
+    combination_B2JpsiK = in_range(5000 * MeV, F.MASS, 6000 * MeV)
+    vertex_B2JpsiK = require_all(
+        in_range(5000 * MeV, F.MASS, 6000 * MeV),
+        (F.OWNPVDIRA > -10.0),
+        (F.CHI2DOF < 10),
+        (F.OWNPVLTIME > 0.2 * picosecond),
+        in_range(1900 * MeV, F.MASS - F.CHILD(1, F.MASS), 2700 * MeV),
+    )
+    b2jpsikplus = ParticleCombiner(
+        Inputs=[jpsi, kplus],
+        DecayDescriptor="[B+ -> J/psi(1S) K+]cc",
+        CombinationCut=combination_B2JpsiK,
+        CompositeCut=vertex_B2JpsiK,
+    )
+
+    b_numerator_onetrack = hlt1_numerator_tistos_filter(
+        hlt1_tis_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"],
+        hlt1_tos_line="Hlt1TrackMVADecision",
+        data=b2jpsikplus,
+    )
+    b_numerator_twotrack = hlt1_numerator_tistos_filter(
+        hlt1_tis_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"],
+        hlt1_tos_line="Hlt1TwoTrackMVADecision",
+        data=b2jpsikplus,
+    )
+    b_tis_on_any = hlt1_tis_on_any_filter(
+        hlt1_trigger_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"],
+        data=b2jpsikplus,
+    )
+    b_tistos_on_any = hlt1_tistos_on_any_filter(
+        hlt1_trigger_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"],
+        data=b2jpsikplus,
+    )
+
+    dict_variables = {
+        "numerator_onetrack": b_numerator_onetrack,
+        "numerator_twotracks": b_numerator_twotrack,
+        "tis_onany": b_tis_on_any,
+        "tistos_onany": b_tistos_on_any,
+    }
+
+    b_hist_list = monitoring_function.monitoring(b2jpsikplus, dict_variables, name)
+
+    return Hlt2Line(
+        name=name,
+        prescale=1,
+        algs=prefilter() + [jpsi, kplus, b2jpsikplus] + b_hist_list,
+        tagging_particles=True,
+        pv_tracks=True,
+        postscale=0,
+        persistreco=True,
+    )
+
+
+@register_line_builder(all_lines)
+def Hlt2TriggerEff_BuToJpsiKplus_JpsiToMuMu_RD_line(
+    name="Hlt2TriggerEff_BuToJpsiKplus_JpsiToMuMu_RD",
+):
+    kaon_pvs = make_pvs()
+    kaon_cuts = F.require_all(
+        F.PT > 250.0 * MeV, F.P > 2.0 * GeV, F.PID_K > 2, F.MINIPCHI2(kaon_pvs) > 9
+    )
+    kaons = ParticleFilter(
+        make_long_kaons(),
+        Cut=F.FILTER(kaon_cuts),
+    )
+
+    muon_pvs = make_pvs()
+    muon_cuts = F.require_all(
+        F.PT > 300.0 * MeV,
+        F.P > 3000.0 * MeV,
+        F.ISMUON,
+        F.PID_MU > 3,
+        F.MINIPCHI2(muon_pvs) > 9,
+    )
+    muon = ParticleFilter(
+        make_long_muons(),
+        name="triggereff_detached_muons_{hash}",
+        Cut=F.FILTER(muon_cuts),
+    )
+
+    jpsi_combination_cut = F.require_all(
+        in_range(0.0 * MeV, F.MASS, 5500.0 * MeV),
+        F.PT > 0.0 * MeV,
+        F.MAXDOCACHI2CUT(30.0),
+    )
+    # jpsi_pvs = make_pvs()
+    jpsi_vertex = F.require_all(F.CHI2DOF < 30.0, F.OWNPVFDCHI2 > 30.0)
+
+    jpsi = ParticleCombiner(
+        [muon, muon],
+        DecayDescriptor="J/psi(1S) -> mu+ mu-",
+        CombinationCut=jpsi_combination_cut,
+        CompositeCut=jpsi_vertex,
+    )
+
+    # pvs = make_pvs()
+    b_cuts = in_range(4000 * MeV, F.MASS, 6500 * MeV)
+    b_vertex_cuts = F.require_all(
+        F.CHI2DOF < 9.0,
+        F.OWNPVIPCHI2 < 25,
+        F.OWNPVFDCHI2 > 100,
+        F.OWNPVDIRA > 0.995,
+    )
+    bu = ParticleCombiner(
+        [jpsi, kaons],
+        DecayDescriptor="[B+ -> J/psi(1S) K+]cc",
+        CombinationCut=b_cuts,
+        CompositeCut=b_vertex_cuts,
+    )
+
+    b_numerator_onetrack = hlt1_numerator_tistos_filter(
+        hlt1_tis_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"],
+        hlt1_tos_line="Hlt1TrackMVADecision",
+        data=bu,
+    )
+    b_numerator_twotrack = hlt1_numerator_tistos_filter(
+        hlt1_tis_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"],
+        hlt1_tos_line="Hlt1TwoTrackMVADecision",
+        data=bu,
+    )
+    b_tis_on_any = hlt1_tis_on_any_filter(
+        hlt1_trigger_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"], data=bu
+    )
+    b_tistos_on_any = hlt1_tistos_on_any_filter(
+        hlt1_trigger_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"], data=bu
+    )
+
+    dict_variables = {
+        "numerator_onetrack": b_numerator_onetrack,
+        "numerator_twotracks": b_numerator_twotrack,
+        "tis_onany": b_tis_on_any,
+        "tistos_onany": b_tistos_on_any,
+    }
+
+    b_hist_list = monitoring_function.monitoring(bu, dict_variables, name)
+
+    return Hlt2Line(
+        name=name,
+        prescale=1,
+        algs=prefilter() + [kaons, jpsi, bu] + b_hist_list,
+        postscale=0,
+        persistreco=True,
+    )
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/triggereff_charm_hlt2.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/triggereff_charm_hlt2.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3ed0d666e42e3179d2d3ad02e55d84d56c9cba4
--- /dev/null
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/triggereff/triggereff_charm_hlt2.py
@@ -0,0 +1,124 @@
+###############################################################################
+# (c) Copyright 2025 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+import Functors as F
+from Functors.math import in_range
+from GaudiKernel.SystemOfUnits import GeV, MeV, mm
+from Moore.config import register_line_builder
+from Moore.lines import Hlt2Line
+from RecoConf.algorithms_thor import ParticleCombiner, ParticleFilter
+from RecoConf.event_filters import require_pvs
+from RecoConf.reconstruction_objects import make_pvs, upfront_reconstruction
+from RecoConf.standard_particles import (
+    make_has_rich_long_kaons,
+    make_has_rich_long_pions,
+    make_long_pions,
+)
+
+from Hlt2Conf.hlt1_tistos import (
+    hlt1_numerator_tistos_filter,
+    hlt1_tis_on_any_filter,
+    hlt1_tistos_on_any_filter,
+)
+
+from . import monitoring_function
+
+all_lines = {}
+
+
+def prefilter():
+    return upfront_reconstruction() + [require_pvs(make_pvs())]
+
+
+@register_line_builder(all_lines)
+def Hlt2TriggerEff_Dstp2D0Pip_D02KmPip_line(name="Hlt2TriggerEff_Dstp2D0Pip_D02KmPip"):
+    kaons_cuts = F.require_all(
+        F.MINIPCHI2CUT(IPChi2Cut=4.0, Vertices=make_pvs()),
+        F.PT > 800 * MeV,
+        F.P > 5 * GeV,
+        F.PID_K > 5.0,
+    )
+    kaons = ParticleFilter(make_has_rich_long_kaons(), F.FILTER(kaons_cuts))
+
+    pions_cuts = F.require_all(
+        F.MINIPCHI2CUT(IPChi2Cut=4.0, Vertices=make_pvs()),
+        F.PT > 800 * MeV,
+        F.P > 5 * GeV,
+        F.PID_K < 5.0,
+    )
+    pions = ParticleFilter(make_has_rich_long_pions(), F.FILTER(pions_cuts))
+
+    dzero_combination = F.require_all(
+        in_range(1685 * MeV, F.MASS, 2045 * MeV),
+        F.PT > 2 * GeV,
+        F.MAX(F.PT) > 1200 * MeV,
+        F.MAXSDOCACUT(0.1 * mm),
+    )
+    dzero_composite = F.require_all(
+        in_range(1715 * MeV, F.MASS, 2015 * MeV),
+        F.CHI2DOF < 10.0,
+        F.OWNPVFDCHI2 > 25.0,
+        F.OWNPVDIRA > 0.99985,
+    )
+    dzeros = ParticleCombiner(
+        [kaons, pions],
+        DecayDescriptor="[D0 -> K- pi+]cc",
+        CombinationCut=dzero_combination,
+        CompositeCut=dzero_composite,
+    )
+
+    pions_dst = ParticleFilter(
+        make_long_pions(), F.FILTER(F.require_all(F.PT > 200 * MeV, F.P > 1 * GeV))
+    )
+    dst_combination = F.MASS - F.CHILD(1, F.MASS) < 165 * MeV
+    dst_composite = F.require_all(
+        F.MASS - F.CHILD(1, F.MASS) < 160 * MeV, F.CHI2DOF < (25.0)
+    )
+    dst = ParticleCombiner(
+        [dzeros, pions_dst],
+        DecayDescriptor="[D*(2010)+ -> D0 pi+]cc",
+        CombinationCut=dst_combination,
+        CompositeCut=dst_composite,
+    )
+
+    numerator_onetrack = hlt1_numerator_tistos_filter(
+        hlt1_tis_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"],
+        hlt1_tos_line="Hlt1TrackMVADecision",
+        data=dzeros,
+    )
+    numerator_twotrack = hlt1_numerator_tistos_filter(
+        hlt1_tis_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"],
+        hlt1_tos_line="Hlt1TwoTrackMVADecision",
+        data=dzeros,
+    )
+    tis_on_any = hlt1_tis_on_any_filter(
+        hlt1_trigger_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"],
+        data=dzeros,
+    )
+    tistos_on_any = hlt1_tistos_on_any_filter(
+        hlt1_trigger_lines=["Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision"],
+        data=dzeros,
+    )
+
+    dict_variables = {
+        "numerator_onetrack": numerator_onetrack,
+        "numerator_twotracks": numerator_twotrack,
+        "tis_onany": tis_on_any,
+        "tistos_onany": tistos_on_any,
+    }
+
+    hist_list = monitoring_function.monitoring(dzeros, dict_variables, name)
+
+    return Hlt2Line(
+        name=name,
+        algs=prefilter() + [dst, dzeros] + hist_list,
+        postscale=0,
+        persistreco=True,
+    )
diff --git a/Hlt/Hlt2Conf/tests/options/streaming/sprucing_physicsstreams_config_check.py b/Hlt/Hlt2Conf/tests/options/streaming/sprucing_physicsstreams_config_check.py
index e2e5f8e1f4f28907b1278cda2d5ae5d23868c62f..9f9e6a71bfee016b4ff2fb82abc3df50a8ae9302 100644
--- a/Hlt/Hlt2Conf/tests/options/streaming/sprucing_physicsstreams_config_check.py
+++ b/Hlt/Hlt2Conf/tests/options/streaming/sprucing_physicsstreams_config_check.py
@@ -56,7 +56,12 @@ def get_hlt2_streaming(hlt2optsdumpfile):
 # Lumi line not to be streamed to disk
 omit_lines = ["Hlt2Lumi"]
 # Monitoring and DQ lines not to be streamed to disk
-turcal_omit_lines = ["Hlt2Monitoring", "Hlt2DQ", "Hlt2CalibMon"] + omit_lines
+turcal_omit_lines = [
+    "Hlt2Monitoring",
+    "Hlt2DQ",
+    "Hlt2CalibMon",
+    "Hlt2TriggerEff",
+] + omit_lines
 
 ##Get HLT2 lines by stream ("Decision" suffix added for TURBO for regex compatibility)
 decisions = get_hlt2_streaming("hlt2_pp_2024_optsdump.py")
diff --git a/Hlt/Hlt2Conf/tests/options/streaming/sprucing_physicsstreams_config_check_pp_ref_2024.py b/Hlt/Hlt2Conf/tests/options/streaming/sprucing_physicsstreams_config_check_pp_ref_2024.py
index 7944e77d9d9abf858967df99c346738630f507cd..387cf8a390b49792301115fd8738cb77ed40a7ea 100644
--- a/Hlt/Hlt2Conf/tests/options/streaming/sprucing_physicsstreams_config_check_pp_ref_2024.py
+++ b/Hlt/Hlt2Conf/tests/options/streaming/sprucing_physicsstreams_config_check_pp_ref_2024.py
@@ -55,7 +55,12 @@ def get_hlt2_streaming(hlt2optsdumpfile):
 # Lumi line not to be streamed to disk
 omit_lines = ["Hlt2Lumi"]
 # Monitoring and DQ lines not to be streamed to disk
-turcal_omit_lines = ["Hlt2Monitoring", "Hlt2DQ", "Hlt2CalibMon"] + omit_lines
+turcal_omit_lines = [
+    "Hlt2Monitoring",
+    "Hlt2DQ",
+    "Hlt2CalibMon",
+    "Hlt2TriggerEff",
+] + omit_lines
 
 ##Get HLT2 lines by stream ("Decision" suffix added for TURBO for regex compatibility)
 decisions = get_hlt2_streaming("hlt2_pp_ref_2024_optsdump.py")