diff --git a/CODEOWNERS b/CODEOWNERS
index 60647c93915a7130ab2739de5be9b7ac00e40f77..6ca68d539388f176bbb46877cb2053918aa679e8 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -137,6 +137,7 @@
 /Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/rare_charm_*.py @dbrundu @dmitzel @smaccoli
 /Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/taggers.py @lpica @mstahl @tpajero
 /Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/d0_to_pi0pi0.py @smaccoli
+/Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/d_to_ksksh.py @gesarpis
 # Inclusive detached dilepton lines
 /Hlt/Hlt2Conf/python/Hlt2Conf/lines/inclusive_detached_dilepton/cutbased_dilepton_*.py @jagoodin
 /Hlt/Hlt2Conf/python/Hlt2Conf/lines/inclusive_detached_dilepton/dilepton_mva_builder.py @lecarus
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/__init__.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/__init__.py
index 9edd2dbf9e3e37361314d335ba08a475c074e29f..3b523a1a989749fb554c1ddf43a3807244475668 100644
--- a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/__init__.py
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/__init__.py
@@ -35,6 +35,7 @@ from . import (
     d_to_hhh,
     d_to_hhhgamma,
     d_to_ksh,
+    d_to_ksksh,
     detection_asymmetry_lines,
     dsstar_to_dspipi,
     dst_to_dee,
@@ -63,6 +64,7 @@ all_lines.update(d_to_etah.all_lines)
 all_lines.update(d_to_hhh.all_lines)
 all_lines.update(d_to_hhhgamma.all_lines)
 all_lines.update(d_to_ksh.all_lines)
+all_lines.update(d_to_ksksh.all_lines)
 all_lines.update(d0_to_hh.all_lines)
 all_lines.update(d0_to_hhgamma.all_lines)
 all_lines.update(d0_to_hhhh.all_lines)
diff --git a/Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/d_to_ksksh.py b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/d_to_ksksh.py
new file mode 100644
index 0000000000000000000000000000000000000000..90141a6ee297af979f0ab5f1fdfc68ffb0e5dacd
--- /dev/null
+++ b/Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/d_to_ksksh.py
@@ -0,0 +1,413 @@
+###############################################################################
+# (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".   #
+#                                                                             #
+# 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.                                       #
+###############################################################################
+"""Following lines are defined:
+
+  1. D+ -> KS0 (-> pi+ pi-) KS0 (-> pi+ pi-) pi+
+  2. D+ -> KS0 (-> pi+ pi-) KS0 (-> pi+ pi-) K+
+  3. D_s+ -> KS0 (-> pi+ pi-) KS0 (-> pi+ pi-) pi+
+  4. D_s+ -> KS0 (-> pi+ pi-) KS0 (-> pi+ pi-) K+
+
+All LLLL, LLDD and DDDD modes of KS are included as a separate lines.
+The D+ and Ds+ decaying to the same final state are included in same line as
+in Run 2.
+
+TODO:
+- check OWNPVIPCHI2 based on the data
+- apply OWNPVLTIME requirements to KS and D(s)+ when functor will be fully working / not flooding logs with warnings
+"""
+
+import Functors as F
+import Functors.math as fmath
+from Functors.math import in_range
+from GaudiKernel.SystemOfUnits import GeV, MeV, mm
+from GaudiKernel.SystemOfUnits import micrometer as um
+from GaudiKernel.SystemOfUnits import picosecond as ps
+from Moore.config import register_line_builder
+from Moore.lines import Hlt2Line
+from RecoConf.algorithms_thor import ParticleCombiner, ParticleFilter
+from RecoConf.reconstruction_objects import make_pvs
+from RecoConf.standard_particles import (
+    make_has_rich_down_pions,
+    make_has_rich_long_kaons,
+    make_has_rich_long_pions,
+    make_KsTT,
+)
+
+from .prefilters import charm_prefilters
+
+# from . import charm_isolation as isolation
+
+all_lines = {}
+
+###################
+## track filters ##
+###################
+
+## The code is based on a similar line: https://gitlab.cern.ch/lhcb/Moore/-/blob/master/Hlt/Hlt2Conf/python/Hlt2Conf/lines/charm/d_to_ksh.py
+
+
+def filter_long_pions(
+    pvs, pt_min=250 * MeV, p_min=2 * GeV, mipchi2_min=4.0, pion_pidk_max=5.0
+):
+    """Filter long pions with P PT, MINIPCHI2CUT and PIDk cuts."""
+    cut = F.require_all(
+        F.PT > pt_min,
+        F.P > p_min,
+        F.MINIPCHI2CUT(IPChi2Cut=mipchi2_min, Vertices=pvs),
+        F.PID_K < pion_pidk_max,
+    )
+    return ParticleFilter(make_has_rich_long_pions(), F.FILTER(cut))
+
+
+def filter_long_kaons(
+    pvs, pt_min=250 * MeV, p_min=3 * GeV, mipchi2_min=4.0, pidk_min=-5.0
+):
+    """Filter long kaons with P PT, MINIPCHI2CUT and PIDk cuts."""
+    cut = F.require_all(
+        F.PT > pt_min,
+        F.P > p_min,
+        F.MINIPCHI2CUT(IPChi2Cut=mipchi2_min, Vertices=pvs),
+        F.PID_K > pidk_min,
+    )
+    return ParticleFilter(make_has_rich_long_kaons(), F.FILTER(cut))
+
+
+def filter_long_pions_from_ks(
+    pvs, pt_min=250 * MeV, p_min=2 * GeV, mipchi2_min=35.0, pion_pidk_max=15.0
+):
+    """Filter long pions with P PT, MINIPCHI2CUT and PIDk cuts."""
+    cut = F.require_all(
+        F.PT > pt_min,
+        F.P > p_min,
+        F.MINIPCHI2CUT(IPChi2Cut=mipchi2_min, Vertices=pvs),
+        F.PID_K < pion_pidk_max,
+    )
+    return ParticleFilter(make_has_rich_long_pions(), F.FILTER(cut))
+
+
+def filter_down_pions_from_ks(pvs, pt_min=250 * MeV, p_min=2 * GeV, pion_pidk_max=15.0):
+    """Filter downstream pions with P PT, and PIDk cuts."""
+    cut = F.require_all(F.PT > pt_min, F.P > p_min, F.PID_K < pion_pidk_max)
+    return ParticleFilter(make_has_rich_down_pions(), F.FILTER(cut))
+
+
+#######################
+## strange combiners ##
+#######################
+def make_ks_ll(
+    pions1,
+    pions2,
+    pvs,
+    name="Charm_DToKsKsH_KsLL_{hash}",
+    comb_m_min=445 * MeV,
+    comb_m_max=550 * MeV,
+    m_min=460 * MeV,
+    m_max=535 * MeV,
+    comb_pt_min=500 * MeV,
+    pt_min=300 * MeV,
+    comb_p_min=3.5 * GeV,
+    p_min=4 * GeV,
+    doca_max=1 * mm,
+    vchi2pdof_max=8.0,
+    ownpvvdz_min=10 * mm,
+    ownpvfdchi2_min=3.0,
+    mipchi2_min=9.0,
+    ownpvltime_min=1.0 * ps,
+):
+    """Make KS -> pi+ pi- from long tracks."""
+    comb_cut = F.require_all(
+        F.MAXDOCACUT(doca_max),
+        in_range(comb_m_min, F.MASS, comb_m_max),
+        F.PT > comb_pt_min,
+        F.P > comb_p_min,
+    )
+    vertex_cut = F.require_all(
+        in_range(m_min, F.MASS, m_max),
+        F.PT > pt_min,
+        F.P > p_min,
+        F.CHI2DOF < vchi2pdof_max,
+        F.OWNPVVDZ > ownpvvdz_min,
+        F.OWNPVFDCHI2 > ownpvfdchi2_min,
+        F.MINIPCHI2CUT(IPChi2Cut=mipchi2_min, Vertices=pvs),
+        F.OWNPVLTIME > ownpvltime_min,
+    )
+    return ParticleCombiner(
+        [pions1, pions2],
+        name=name,
+        DecayDescriptor="KS0 -> pi+ pi-",
+        CombinationCut=comb_cut,
+        CompositeCut=vertex_cut,
+    )
+
+
+def make_ks_dd(
+    pions1,
+    pions2,
+    name="Charm_DToKsKsH_KsDD_{hash}",
+    comb_m_min=417 * MeV,
+    comb_m_max=577 * MeV,
+    m_min=437 * MeV,
+    m_max=557 * MeV,
+    comb_pt_min=500 * MeV,
+    pt_min=450 * MeV,
+    sum_pt_min=500 * MeV,
+    comb_p_min=4.5 * GeV,
+    p_min=5 * GeV,
+    doca_max=2 * mm,
+    docachi2_max=12.0,
+    vchi2pdof_max=8.0,
+    mipchi2_min=9.0,
+    ownpvltime_min=1.0 * ps,
+):
+    """
+    Make KS -> pi+ pi- from downstream tracks.
+    """
+    comb_cut = F.require_all(
+        F.MAXDOCACUT(doca_max),
+        F.MAXDOCACHI2CUT(docachi2_max),
+        in_range(comb_m_min, F.MASS, comb_m_max),
+        F.PT > comb_pt_min,
+        F.SUM(F.PT) > sum_pt_min,
+        F.P > comb_p_min,
+    )
+    vertex_cut = F.require_all(
+        in_range(m_min, F.MASS, m_max),
+        F.PT > pt_min,
+        F.P > p_min,
+        F.CHI2DOF < vchi2pdof_max,
+        F.OWNPVLTIME > ownpvltime_min,
+    )
+    return ParticleCombiner(
+        [pions1, pions2],
+        name=name,
+        DecayDescriptor="KS0 -> pi+ pi-",
+        CombinationCut=comb_cut,
+        CompositeCut=vertex_cut,
+    )
+
+
+########################
+## D mesons combiners ##
+########################
+def combine_d_ks_ks_h(
+    ks0,
+    ks1,
+    particle,
+    pvs,
+    decay_descriptor,
+    name="Charm_DToKsKsH_DToKsKsHCombiner_{hash}",
+    comb_m_min=1765 * MeV,
+    comb_m_max=2065 * MeV,
+    m_min=1840 * MeV,  # lower range for D+
+    m_max=2090 * MeV,  # upper range for Ds+
+    comb_pt_min=3 * GeV,
+    pt_min=2.0 * GeV,
+    sum_pt_min=1.5 * GeV,
+    comb_p_min=20 * GeV,
+    p_min=16 * GeV,
+    doca_max=100 * um,
+    vchi2pdof_max=8.0,
+    ownpvltime_min=0.4 * ps,
+    ownpvvdz_min=0.5 * mm,
+    ownpvfdchi2_min=25.0,
+    bpfdrho_max=5 * mm,
+    ownpvdira_min=0.9995,
+    dz1_min=20.0 * mm,
+    ks_fdrho_min=1 * mm,
+    dzero_vz_min=-300 * mm,
+):
+    """Combine D meson with Ks Ks and additonal hadron (K/pi).
+    Make MASS, P, PT, SUM(PT), MAXDOCACUT cuts in the combination;
+    MASS, P, PT, CHI2DOF, OWNPVVDZ, OWNPVFDCHI2, OWNPVIPCHI2, OWNPVDIRA cuts after the vertex fit.
+    Cuts generally based on Run2 Turbo lines.
+    """
+    comb_cut = F.require_all(
+        in_range(comb_m_min, F.MASS, comb_m_max),
+        F.PT > comb_pt_min,
+        F.SUM(F.PT) > sum_pt_min,
+        F.P > comb_p_min,
+    )
+
+    if doca_max is not None:
+        comb_cut &= F.MAXSDOCACUT(doca_max)
+
+    vertex_cut = F.require_all(
+        in_range(m_min, F.MASS, m_max),
+        F.END_VZ > dzero_vz_min,
+        F.OWNPVVDRHO < bpfdrho_max,
+        F.PT > pt_min,
+        F.P > p_min,
+        F.CHI2DOF < vchi2pdof_max,
+        F.OWNPVLTIME > ownpvltime_min,
+        F.OWNPVVDZ > ownpvvdz_min,
+        F.OWNPVFDCHI2 > ownpvfdchi2_min,
+        F.OWNPVDIRA > ownpvdira_min,
+        F.CHILD(1, F.END_VZ) - F.END_VZ > dz1_min,
+        fmath.sqrt(
+            (F.CHILD(1, F.END_VX) - F.END_VX) ** 2
+            + (F.CHILD(1, F.END_VY) - F.END_VY) ** 2
+        )
+        > ks_fdrho_min,
+        F.CHILD(2, F.END_VZ) - F.END_VZ > dz1_min,
+        fmath.sqrt(
+            (F.CHILD(2, F.END_VX) - F.END_VX) ** 2
+            + (F.CHILD(2, F.END_VY) - F.END_VY) ** 2
+        )
+        > ks_fdrho_min,
+    )
+    return ParticleCombiner(
+        [ks0, ks1, particle],
+        name=name,
+        AllowDiffInputsForSameIDChildren=True,
+        DecayDescriptor=decay_descriptor,
+        CombinationCut=comb_cut,
+        CompositeCut=vertex_cut,
+    )
+
+
+###########################
+## Hlt2 lines definition ##
+###########################
+@register_line_builder(all_lines)
+def dp_to_kskspi_llll_line(name="Hlt2Charm_DpDspToKsKsPip_LLLL", prescale=1):
+    pvs = make_pvs()
+    long_pions = filter_long_pions(pvs)
+    ks_ll = make_ks_ll(
+        filter_long_pions_from_ks(pvs), filter_long_pions_from_ks(pvs), pvs
+    )
+    dp_kskspi_llll = combine_d_ks_ks_h(
+        ks_ll,
+        ks_ll,
+        long_pions,
+        pvs,
+        "[D+ -> KS0 KS0 pi+]cc",
+        name=f"{name}_Combiner",
+    )
+    return Hlt2Line(
+        name=name,
+        algs=charm_prefilters() + [ks_ll, dp_kskspi_llll],
+        prescale=prescale,
+    )
+
+
+@register_line_builder(all_lines)
+def dp_to_kskspi_lldd_line(name="Hlt2Charm_DpDspToKsKsPip_LLDD", prescale=1):
+    pvs = make_pvs()
+    long_pions = filter_long_pions(pvs)
+    ks_ll = make_ks_ll(
+        filter_long_pions_from_ks(pvs), filter_long_pions_from_ks(pvs), pvs
+    )
+    ks_dd = make_ks_dd(filter_down_pions_from_ks(pvs), filter_down_pions_from_ks(pvs))
+    dp_kskspi_lldd = combine_d_ks_ks_h(
+        ks_ll,
+        ks_dd,
+        long_pions,
+        pvs,
+        "[D+ -> KS0 KS0 pi+]cc",
+        name=f"{name}_Combiner",
+        doca_max=2.0 * mm,
+        dz1_min=50.0 * mm,
+        ks_fdrho_min=10 * mm,
+    )
+    return Hlt2Line(
+        name=name,
+        algs=charm_prefilters() + [ks_ll, ks_dd, dp_kskspi_lldd],
+        prescale=prescale,
+    )
+
+
+@register_line_builder(all_lines)
+def dp_to_kskspi_dddd_line(name="Hlt2Charm_DpDspToKsKsPip_DDDD", prescale=1):
+    pvs = make_pvs()
+    long_pions = filter_long_pions(pvs)
+    ks_dd = make_ks_dd(filter_down_pions_from_ks(pvs), filter_down_pions_from_ks(pvs))
+    dp_kskspi_dddd = combine_d_ks_ks_h(
+        ks_dd,
+        ks_dd,
+        long_pions,
+        pvs,
+        "[D+ -> KS0 KS0 pi+]cc",
+        name=f"{name}_Combiner",
+        doca_max=2.0 * mm,
+        dz1_min=50.0 * mm,
+        ks_fdrho_min=10 * mm,
+    )
+    return Hlt2Line(
+        name=name, algs=charm_prefilters() + [ks_dd, dp_kskspi_dddd], prescale=prescale
+    )
+
+
+@register_line_builder(all_lines)
+def dp_to_kskskp_llll_line(name="Hlt2Charm_DpDspToKsKsKp_LLLL", prescale=1):
+    pvs = make_pvs()
+    long_kaons = filter_long_kaons(pvs)
+    ks_ll = make_ks_ll(
+        filter_long_pions_from_ks(pvs), filter_long_pions_from_ks(pvs), pvs
+    )
+    dp_kskskp_llll = combine_d_ks_ks_h(
+        ks_ll,
+        ks_ll,
+        long_kaons,
+        pvs,
+        "[D+ -> KS0 KS0 K+]cc",
+        name=f"{name}_Combiner",
+    )
+    return Hlt2Line(
+        name=name, algs=charm_prefilters() + [ks_ll, dp_kskskp_llll], prescale=prescale
+    )
+
+
+@register_line_builder(all_lines)
+def dp_to_kskskp_lldd_line(name="Hlt2Charm_DpDspToKsKsKp_LLDD", prescale=1):
+    pvs = make_pvs()
+    long_kaons = filter_long_kaons(pvs)
+    ks_ll = make_ks_ll(
+        filter_long_pions_from_ks(pvs), filter_long_pions_from_ks(pvs), pvs
+    )
+    ks_dd = make_ks_dd(filter_down_pions_from_ks(pvs), filter_down_pions_from_ks(pvs))
+    dp_kskskp_lldd = combine_d_ks_ks_h(
+        ks_ll,
+        ks_dd,
+        long_kaons,
+        pvs,
+        "[D+ -> KS0 KS0 K+]cc",
+        name=f"{name}_Combiner",
+        doca_max=2.0 * mm,
+        dz1_min=50.0 * mm,
+        ks_fdrho_min=10 * mm,
+    )
+    return Hlt2Line(
+        name=name,
+        algs=charm_prefilters() + [ks_ll, ks_dd, dp_kskskp_lldd],
+        prescale=prescale,
+        # extra_outputs=isolation.make_iso_particles(dp_kskp_ld, coneangle=0.5, DownstreamTrackIso=True)
+    )
+
+
+@register_line_builder(all_lines)
+def dp_to_kskskp_dddd_line(name="Hlt2Charm_DpDspToKsKsKp_DDDD", prescale=1):
+    pvs = make_pvs()
+    long_kaons = filter_long_kaons(pvs)
+    ks_dd = make_ks_dd(filter_down_pions_from_ks(pvs), filter_down_pions_from_ks(pvs))
+    dp_kskskp_dddd = combine_d_ks_ks_h(
+        ks_dd,
+        ks_dd,
+        long_kaons,
+        pvs,
+        "[D+ -> KS0 KS0 K+]cc",
+        name=f"{name}_Combiner",
+        doca_max=2.0 * mm,
+        dz1_min=50.0 * mm,
+        ks_fdrho_min=10 * mm,
+    )
+    return Hlt2Line(
+        name=name, algs=charm_prefilters() + [ks_dd, dp_kskskp_dddd], prescale=prescale
+    )