diff --git a/VHR/vhrbase.py b/VHR/vhrbase.py
index d5b2942d678bac77e2fd652e79b8cd81fb558abe..89f58ed20f02f3720a028fa9ccc142bbd6c7657e 100644
--- a/VHR/vhrbase.py
+++ b/VHR/vhrbase.py
@@ -228,3 +228,48 @@ class SPOT67RasterPipeline:
             self.types = self.types[:pipe_length]
             self.out_p = self.out_p[:pipe_length]
         return out
+
+class PleiadesOrthoPipeline(SPOT67RasterPipeline):
+    # BEGIN PLEIADES (ORT) VHR PROTOTYPE
+    MS_FOLDER_PATTERN = 'IMG_PHR*_MS_*'
+    PAN_FOLDER_PATTERN = 'IMG_PHR*_P_*'
+    TILE_PATTERN = '*_R*C*.TIF'
+    NDT = 0.0
+    REF_TYPE = otb.ImagePixelType_uint16
+    MS_LABEL = 'MS'
+    OPT_IN = ''
+
+class PleiadesOrthoAutoMosaicPipeline:
+    def __init__(self, mosaic_root, pattern, out_fld):
+        lst = sorted(glob.glob(os.path.join(mosaic_root, pattern)))
+        lst = [x for x in lst if os.path.isdir(x)]
+        self.scene_list = [PleiadesOrthoPipeline(x) for x in lst]
+        self.processed_scenes = []
+        self.out_fld = out_fld
+
+    def process_scenes(self, roi=None, compress=False):
+        for s in self.scene_list:
+            s.to_toa()
+            if roi is not None and os.path.exists(roi):
+                s.clip(roi)
+            s.write_outputs(self.out_fld, update_pipe=True, compress=compress)
+            s.pansharp()
+            self.processed_scenes.extend(s.write_outputs(self.out_fld, compress=compress))
+        return
+    
+    def generate_mosaic(self, vrt=True):
+        if len(self.processed_scenes) > 0:
+            lst = self.processed_scenes
+            fn = lst[0].split('_')
+            fn[-3] = 'MOSAIC'
+            fn = '_'.join(fn)
+            if vrt is True:
+                vrtopt = gdal.BuildVRTOptions()
+                fn = fn.replace('.TIF', '.vrt')
+                gdal.BuildVRT(fn, lst, options=vrtopt)
+            else:
+                print('Not implemented yet.')
+            return fn
+        else:
+            print('Preprocess scenes first.')
+            return None
\ No newline at end of file
diff --git a/Workflows/operations.py b/Workflows/operations.py
index 3117b65d0afa16524df25486f5e014d473a7d55c..0117e52d8fc96ab05767a46af32ed6ecdcce8991 100644
--- a/Workflows/operations.py
+++ b/Workflows/operations.py
@@ -32,6 +32,24 @@ def preprocess_spot67(in_fld, out_fld, dem_fld, geoid_file, skip_ps, compress,
         sp.rigid_align(align_to, this_band=align_using_band-1, ref_band=align_to_band-1)
     return sp.write_outputs(out_fld, compress=compress)
 
+def preprocess_pleiades(in_fld, out_fld, skip_ps, compress, clip, 
+                        align_to=None, align_to_band=3, align_using_band=1):
+    sp = VHR.vhrbase.PleiadesOrthoPipeline(in_fld)
+    sp.to_toa()
+    if clip is not None and os.path.exists(clip):
+        sp.clip(clip)
+    if not skip_ps:
+        sp.write_outputs(out_fld, update_pipe=True, compress=compress)
+        sp.pansharp()
+    if align_to is not None and os.path.exists(align_to):
+        sp.rigid_align(align_to, this_band=align_using_band-1, ref_band=align_to_band-1)
+    return sp.write_outputs(out_fld, compress=compress)
+
+def preprocess_pleiades_mosaic(in_fld, out_fld, pattern):
+    sp = VHR.vhrbase.PleiadesOrthoAutoMosaicPipeline(in_fld, pattern, out_fld)
+    sp.process_scenes()
+    return sp.generate_mosaic()
+
 def preprocess_s2(in_fld, out_fld, output_dates_file=None, roi=None,
                   align_to=None, align_to_band=3, align_using_band=3, provider='theia'):
     S2Processor = None
diff --git a/moringa.py b/moringa.py
index 771c3b52fed8f068645beb114d34a84149da8adc..69d271ca91fcc9c42e06df78dea6328495ac3377 100755
--- a/moringa.py
+++ b/moringa.py
@@ -48,6 +48,23 @@ def main(args):
     vhrprep.add_argument("--skip_ps", help="Skip pansharpening step.", action='store_true')
     vhrprep.add_argument("--compress", help="Use lossless compression on outputs.", action='store_true')
 
+    plprep = subpar.add_parser("preprocess_pleiades", help="Perform baseline pre-processing of a Pleaides ortho scene.",
+                                formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    plprep.add_argument("fld", type=str, help="Path to the root folder containing PAN and MS subfolders.")
+    plprep.add_argument("out_fld", type=str, help="Path to the output folder for preprocessed images.")
+    plprep.add_argument("--clip", type=str, default=None, help="Path to a vector file for clipping.")
+    plprep.add_argument("--align_to", type=str, default=None, help="Path to a reference image to which the image must be aligned (rigid).")
+    plprep.add_argument("--align_to_band", type=int, default=3, help="Band of reference image used for alignment.")
+    plprep.add_argument("--align_using_band", type=int, default=1, help="Band of current image used for alignment.")
+    plprep.add_argument("--skip_ps", help="Skip pansharpening step.", action='store_true')
+    plprep.add_argument("--compress", help="Use lossless compression on outputs.", action='store_true')
+
+    plmprep = subpar.add_parser("preprocess_pleiades_mosaic", help="Perform baseline pre-processing and auto-mosaic of Pleaides ortho scenes.",
+                                formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    plmprep.add_argument("fld", type=str, help="Path to the root folder containing Pleaides acquisitions.")
+    plmprep.add_argument("pattern", type=str, help="File pattern to collect scene folders within in_fld.")
+    plmprep.add_argument("out_fld", type=str, help="Path to the output folder for preprocessed images.")
+
     s1prepr = subpar.add_parser("preprocess_s1", help="Performs Moringa preset time series preprocessing for Sentinel-1.",
                                 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
     s1prepr.add_argument("in_folder", type=str, help="Path to the folder containing (de-zipped) S1 images.")
@@ -125,6 +142,13 @@ def main(args):
     if arg.cmd == "preprocess_spot67":
         preprocess_spot67(arg.fld, arg.out_fld, arg.dem_fld, arg.geoid, arg.skip_ps, arg.compress,
                           arg.clip, arg.align_to, arg.align_to_band, arg.align_using_band)
+    
+    if arg.cmd == "preprocess_pleiades":
+        preprocess_pleiades(arg.fld, arg.out_fld, arg.skip_ps, arg.compress, arg.clip, 
+                          arg.align_to, arg.align_to_band, arg.align_using_band)
+        
+    if arg.cmd == "preprocess_pleiades_mosaic":
+        preprocess_pleiades_mosaic(arg.fld, arg.out_fld, arg.pattern)
 
     if arg.cmd == "preprocess_s1":
         preprocess_s1(arg.in_folder, arg.roi, arg.out_folder, arg.dem_fld, arg.geoid, arg.direction, arg.satellite,