diff --git a/climax/core/cli.py b/climax/core/cli.py
new file mode 100644
index 0000000000000000000000000000000000000000..a3c7f5f6b22043815869b4b9c6e3b04f91032080
--- /dev/null
+++ b/climax/core/cli.py
@@ -0,0 +1,78 @@
+"""Command line argument parsers."""
+
+# !/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# builtins
+import argparse
+import logging
+import pathlib
+
+# locals
+from climax.core.constants import CORDEX_VARIABLES, CDO_RESAMPLING_MODES
+
+# epilogue to display at the end of each parser
+EPILOGUE = 'Author: Daniel Frisinghelli, daniel.frisinghelli@gmail.com'
+
+# module level logger
+LOGGER = logging.getLogger(__name__)
+
+
+# parser to preprocess Cordex data: climax.main.preprocess.py
+def preprocess_parser():
+
+    # define command line argument parser
+    parser = argparse.ArgumentParser(
+        description='Reproject and resample Cordex data to a target grid.',
+        epilog=EPILOGUE,
+        formatter_class=lambda prog: argparse.RawDescriptionHelpFormatter(
+            prog, max_help_position=50, indent_increment=2))
+
+    # positional arguments
+
+    # positional argument: path to the target grid file
+    parser.add_argument('grid', type=pathlib.Path,
+                        help='Path to the target grid file.')
+
+    # positional argument: name of the variable of interest
+    parser.add_argument('variable', type=str,
+                        help='Name of the variable of interest.',
+                        choices=CORDEX_VARIABLES)
+
+    # positional argument: path to search for Cordex NetCDF files
+    parser.add_argument('source', type=pathlib.Path,
+                        help='Path to search for Cordex NetCDF files.')
+
+    # positional argument: path to save the reprojected NetCDF files
+    parser.add_argument('target', type=pathlib.Path,
+                        help='Path to save the remapped Cordex NetCDF files.')
+
+    # optional arguments
+
+    # default values
+    default = '(default: %(default)s)'
+
+    # optional argument: resampling mode
+    parser.add_argument('-m', '--mode', type=str,
+                        help='Resampling mode {}.'.format(default),
+                        default='bilinear', choices=CDO_RESAMPLING_MODES,
+                        metavar='')
+
+    # optional argument: file pattern to search for in source directory
+    parser.add_argument('-p', '--pattern', type=str,
+                        help=('(Regex) file pattern to search for in the '
+                              'source directory {}.'.format(default)),
+                        default='(.*).nc$', metavar='')
+
+    # optional argument: whether to overwrite files
+    parser.add_argument('-o', '--overwrite', type=bool,
+                        help='Overwrite existing files {}.'.format(default),
+                        default=False, nargs='?', const=True, metavar='')
+
+    # optional argument: dry run, print files which would be processed
+    parser.add_argument('-d', '--dry-run', type=bool,
+                        help=('Print files which would be processed {}.'
+                              .format(default)), default=False, nargs='?',
+                        const=True, metavar='')
+
+    return parser