diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 73e24cf6626d8399d1f86a9f99a3f7dcca5dd60e..ac219a78d332db7116531f0207ee88888611d64d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,6 +9,7 @@ include:
     -   local: 'templates/python/code_quality/isort/isort.yml'
     -   local: 'templates/python/code_quality/mypy/mypy.yml'
     -   local: 'templates/python/code_quality/ruff/ruff.yml'
+    -   local: 'templates/python/dependency_management/requirements-compile/requirements-compile.yml'
 
 python_install:
     extends:
@@ -57,3 +58,11 @@ ruff:
     needs: [ "python_install" ]
     variables:
         PROJECT_PATH: "tests/ruff_project"
+
+requirements-compile:
+    stage: templates
+    needs: [ "python_install" ]
+    variables:
+        PROJECT_PATH: "tests/requirements-compile_project"
+        REQUIREMENTS_FILE_PATH: "${PROJECT_PATH}/requirements.in"
+        OUTPUT_FILE_PATH: "${PROJECT_PATH}/requirements.txt"
diff --git a/AUTHORS.rst b/AUTHORS.rst
index bddd8b1893f285517eb9c8181d41b16ee5c3a3e2..2d3d9d2fcc3afa66ab618d849c5c9484dbbc33ef 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -10,4 +10,4 @@ Development Lead
 Contributors
 ------------
 
-None yet. Why not be the first?
+* Simon Desnoe <0d3s3n@gmail.com>
diff --git a/pyproject.toml b/pyproject.toml
index 8e52531e530ce394f08c59a2e551d8907b3c3915..61f7768f48ea66d41bffd1193571667dee581593 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,6 +22,8 @@ dependencies = [
 
 [project.optional-dependencies]
 QUALITY = [
+    "black",
+    "mypy",
     "pre-commit",
 ]
 
@@ -29,3 +31,10 @@ QUALITY = [
 strict-config = true
 plugins.line-length.enabled = false
 
+[[tool.mypy.overrides]]
+module = [
+    "packaging.requirements",
+    "packaging.specifiers",
+    "packaging",
+]
+ignore_missing_imports = true
\ No newline at end of file
diff --git a/r2_metadata/requirements-compile.r2.yml b/r2_metadata/requirements-compile.r2.yml
new file mode 100644
index 0000000000000000000000000000000000000000..729ed0f49f8e9aa72e58ceb0ea4abf8997e16675
--- /dev/null
+++ b/r2_metadata/requirements-compile.r2.yml
@@ -0,0 +1,16 @@
+files:
+    template: ../templates/python/dependency_management/requirements-compile/requirements-compile.yml
+    documentation: ../templates/python/dependency_management/requirements-compile/README.md
+    changelog: ../templates/python/dependency_management/requirements-compile/CHANGELOG.md
+data:
+    description: "Run pip-compile to generate a requirements.txt and create a merge 
+        request on your repository with the updated requirements.txt"
+    icon: âš«
+    public: true
+    labels:
+        - Utilities
+        - Dependency management
+        - Gitlab
+        - Python
+    license: MIT
+    deprecated: false
diff --git a/templates/python/dependency_management/requirements-compile/CHANGELOG.md b/templates/python/dependency_management/requirements-compile/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..31e92f039b5e5f9a1c909308d5e054b6276513e8
--- /dev/null
+++ b/templates/python/dependency_management/requirements-compile/CHANGELOG.md
@@ -0,0 +1,7 @@
+# Changelog
+
+All notable changes to this job will be documented in this file
+
+## [0.1.0] - 2023-09-05
+
+* Initial version
diff --git a/templates/python/dependency_management/requirements-compile/README.md b/templates/python/dependency_management/requirements-compile/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..45497f5dedbe30b9c90db9f47ea4376171b8751e
--- /dev/null
+++ b/templates/python/dependency_management/requirements-compile/README.md
@@ -0,0 +1,44 @@
+# requirements-compile template
+
+## Objective
+
+The objective of the `requirements-compile` job is to provide a way to update the
+requirements.txt file and create a merge request on a Gitlab instance. This reusable job
+can help speed up other jobs creation and ensure consistent configuration across CI
+jobs.
+
+## How to use it
+
+1. Include the requirements-compile template in your CI/CD configuration (see quick use
+   above).
+2. Create a job that extend the `requirements-compile` job template.
+3. If you need to customize the job, check
+   the [jobs customization](https://docs.r2devops.io/get-started/use-templates/#job-templates-customization).
+
+## Variables
+
+| Name                     | Description                                                                                                                                                   | Default                              |
+|--------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------|
+| `PROJECT_PATH`           | The path to the project root directory.                                                                                                                       | `"."`                                |
+| `REQUIREMENTS_FILE_PATH` | the path to the requirements file.                                                                                                                            | `"${PROJECT_PATH}/requirements.txt"` |
+| `IMAGE_TAG`              | The default tag for the docker image. See [Python Docker Official Image](https://hub.docker.com/_/python) for supported tags and respective Dockerfile links. | `"latest"`                           |
+| `GITLAB_API_URL`         | The host name of the GitLab instance                                                                                                                          | `${CI_SERVER_HOST}`                  |
+
+## Example of use
+
+```yaml
+include:
+    # Include the python_install job template (don't forget to replace the version tag)
+    -   remote: 'https://api.r2devops.io/job/r/gitlab/dorianturba/r2devops_catalog/r2_metadata/requirements-compile@0.1.0.yaml'
+
+requirements311:
+    extends:
+        - .requirements-compile  # extends the python_install job template
+    stage: dependency_management
+    variables:
+        REQUIREMENTS_FILE_PATH: "${PROJECT_PATH}/requirements-py312.txt"  # override the default REQUIREMENTS_FILE_PATH variable
+        IMAGE_TAG: "3.12" # override the default IMAGE_TAG variable
+        GITLAB_API_URL: "gitlab.example.com" # override the default GITLAB_API_URL
+    script:
+        - !reference [ script ]  # reuse the script from the requirements-compile job template
+```
diff --git a/templates/python/dependency_management/requirements-compile/requirements-compile.yml b/templates/python/dependency_management/requirements-compile/requirements-compile.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c2b1b388e6108cbae47a1827aab05e462cf35c20
--- /dev/null
+++ b/templates/python/dependency_management/requirements-compile/requirements-compile.yml
@@ -0,0 +1,51 @@
+include:
+    - remote: 'https://api.r2devops.io/job/r/gitlab/dorianturba/r2devops_catalog/r2_metadata/python_install@latest.yaml'
+
+requirements-compile:
+    extends:
+        - .python_install
+    stage: build
+    image: python:${IMAGE_TAG}
+
+    variables:
+        PYTHON_SETUP: pip install pip-tools requirements-compare
+        GITLAB_API_URL: "${CI_SERVER_HOST}"
+        REQUIREMENTS_FILE_PATH: "${PROJECT_PATH}/requirements.in"
+        OUTPUT_FILE_PATH: "${PROJECT_PATH}/requirements${IMAGE_TAG}.txt"
+        CI_DEBUG_TRACE: "true"
+
+    script:
+        - !reference [.python_install, script]
+        - DEPS_BRANCH="requirements-compile/requirements-txt/$(date +%s)"
+        - |
+            COMMIT_MESSAGE="build(deps): bump new versions"
+        - $([ -f ${OUTPUT_FILE_PATH} ]) && ACTION="update" || ACTION="create"
+        - pip-compile --quiet --strip-extras -o ${OUTPUT_FILE_PATH} ${REQUIREMENTS_FILE_PATH}
+        - if [ -n "$(git status --porcelain ${OUTPUT_FILE_PATH})" ]; then
+        - |
+            curl --header "Authorization: Bearer ${REQUIREMENTS_COMPILE_TOKEN}" \
+            --form "branch=$DEPS_BRANCH" \
+            --form "ref=${CI_DEFAULT_BRANCH}" \
+            "https://${GITLAB_API_URL}/api/v4/projects/${CI_PROJECT_ID}/repository/branches"
+        - |
+            curl --header "Authorization: Bearer ${REQUIREMENTS_COMPILE_TOKEN}" \
+            --form "branch=$DEPS_BRANCH" \
+            --form "commit_message=$COMMIT_MESSAGE" \
+            --form "actions[][action]=$ACTION" \
+            --form "actions[][file_path]=${OUTPUT_FILE_PATH}" \
+            --form "actions[][content]=<${OUTPUT_FILE_PATH}" \
+            "https://${GITLAB_API_URL}/api/v4/projects/${CI_PROJECT_ID}/repository/commits"
+        - requirements_compare ${OUTPUT_FILE_PATH}  # Debug
+        - requirements_compare ${OUTPUT_FILE_PATH} > description.md
+        - |
+            curl --header "Authorization: Bearer ${REQUIREMENTS_COMPILE_TOKEN}" \
+            --form "source_branch=$DEPS_BRANCH" \
+            --form "target_branch=${CI_DEFAULT_BRANCH}" \
+            --form "title=$COMMIT_MESSAGE" \
+            --form "description=<description.md" \
+            "https://${GITLAB_API_URL}/api/v4/projects/${CI_PROJECT_ID}/merge_requests"
+        - fi
+    
+
+
+
diff --git a/tests/flake8_project/src/flake8_project/__init__.py b/tests/flake8_project/src/flake8_project/__init__.py
index 58505af1f84165e36769758d2fe06f4cdc2b1a0e..22ee9155c7c60b928c68eaf1fdb321ed3f638a83 100644
--- a/tests/flake8_project/src/flake8_project/__init__.py
+++ b/tests/flake8_project/src/flake8_project/__init__.py
@@ -1,3 +1,3 @@
 from flake8_project.main import main
 
-__all__ = ['main']
+__all__ = ["main"]
diff --git a/tests/flake8_project/src/flake8_project/main.py b/tests/flake8_project/src/flake8_project/main.py
index 28caf00b6f3b52955a2bc069b315fe44940eabb8..250de775d1c9fcfd14cf1b50313c5e872521be9f 100644
--- a/tests/flake8_project/src/flake8_project/main.py
+++ b/tests/flake8_project/src/flake8_project/main.py
@@ -7,5 +7,5 @@ def main() -> bool:
     return True
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()
diff --git a/tests/isort_project/src/isort_project/z_module.py b/tests/isort_project/src/isort_project/z_module.py
index 651a32811b82c11d6e60c6021cddb6ff34008867..b8f1ab80d341118568895ad2e3264e9166bd6219 100644
--- a/tests/isort_project/src/isort_project/z_module.py
+++ b/tests/isort_project/src/isort_project/z_module.py
@@ -1,2 +1,2 @@
 def barfoo():
-    ...
\ No newline at end of file
+    ...
diff --git a/tests/pytest_project/src/pytest_project/__init__.py b/tests/pytest_project/src/pytest_project/__init__.py
index d4cc63e287d1f9b8e3f12a55c9a24e34eb3241c3..c835af4b921fc971797af114b2008373041b26eb 100644
--- a/tests/pytest_project/src/pytest_project/__init__.py
+++ b/tests/pytest_project/src/pytest_project/__init__.py
@@ -1,3 +1,3 @@
 from pytest_project.main import main
 
-__all__ = ['main']
+__all__ = ["main"]
diff --git a/tests/pytest_project/src/pytest_project/main.py b/tests/pytest_project/src/pytest_project/main.py
index 28caf00b6f3b52955a2bc069b315fe44940eabb8..250de775d1c9fcfd14cf1b50313c5e872521be9f 100644
--- a/tests/pytest_project/src/pytest_project/main.py
+++ b/tests/pytest_project/src/pytest_project/main.py
@@ -7,5 +7,5 @@ def main() -> bool:
     return True
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()
diff --git a/tests/python_install_project/src/python_install_project/__init__.py b/tests/python_install_project/src/python_install_project/__init__.py
index d4cc63e287d1f9b8e3f12a55c9a24e34eb3241c3..c835af4b921fc971797af114b2008373041b26eb 100644
--- a/tests/python_install_project/src/python_install_project/__init__.py
+++ b/tests/python_install_project/src/python_install_project/__init__.py
@@ -1,3 +1,3 @@
 from pytest_project.main import main
 
-__all__ = ['main']
+__all__ = ["main"]
diff --git a/tests/python_install_project/src/python_install_project/main.py b/tests/python_install_project/src/python_install_project/main.py
index 28caf00b6f3b52955a2bc069b315fe44940eabb8..250de775d1c9fcfd14cf1b50313c5e872521be9f 100644
--- a/tests/python_install_project/src/python_install_project/main.py
+++ b/tests/python_install_project/src/python_install_project/main.py
@@ -7,5 +7,5 @@ def main() -> bool:
     return True
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()
diff --git a/tests/requirements-compile_project/requirements.in b/tests/requirements-compile_project/requirements.in
new file mode 100644
index 0000000000000000000000000000000000000000..f2293605cf1b01dca72aad0a15c45b72ed5429a2
--- /dev/null
+++ b/tests/requirements-compile_project/requirements.in
@@ -0,0 +1 @@
+requests
diff --git a/tests/requirements-compile_project/test_requirements.in b/tests/requirements-compile_project/test_requirements.in
new file mode 100644
index 0000000000000000000000000000000000000000..e079f8a6038dd2dc8512967540f96ee0de172067
--- /dev/null
+++ b/tests/requirements-compile_project/test_requirements.in
@@ -0,0 +1 @@
+pytest
diff --git a/tests/ruff_project/src/ruff_project/__init__.py b/tests/ruff_project/src/ruff_project/__init__.py
index 58505af1f84165e36769758d2fe06f4cdc2b1a0e..22ee9155c7c60b928c68eaf1fdb321ed3f638a83 100644
--- a/tests/ruff_project/src/ruff_project/__init__.py
+++ b/tests/ruff_project/src/ruff_project/__init__.py
@@ -1,3 +1,3 @@
 from flake8_project.main import main
 
-__all__ = ['main']
+__all__ = ["main"]
diff --git a/tests/ruff_project/src/ruff_project/main.py b/tests/ruff_project/src/ruff_project/main.py
index 28caf00b6f3b52955a2bc069b315fe44940eabb8..250de775d1c9fcfd14cf1b50313c5e872521be9f 100644
--- a/tests/ruff_project/src/ruff_project/main.py
+++ b/tests/ruff_project/src/ruff_project/main.py
@@ -7,5 +7,5 @@ def main() -> bool:
     return True
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()