diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 36dd190f15721ddd0dc5c8cbdf0eba75ab7902c9..80ad328f094433833f53a5512cfc85f93eb799a5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,245 +1,4 @@
-workflow:
-  rules:
-    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
-    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
-    - if: $CI_COMMIT_TAG
-
-variables:
-  PYTHONUNBUFFERED: "1"
-  XDG_CACHE_HOME: "${CI_PROJECT_DIR}/cache"
-  CITOOLS: "git+https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.idiap.ch/bob/citools"
-
-default:
-  tags:
-    - bob
-    - docker
-  image: python:3.10
-
-stages:
-  - qa
-  - test
-  - doc
-  - dist
-  - deploy
-
-quality:
-  stage: qa
-  before_script:
-    - python3 -m venv venv
-    - source venv/bin/activate
-    - pip install pre-commit
-  script:
-    - pre-commit run --all-files --show-diff-on-failure --verbose
-  needs: []
-  cache:
-    key: pre-commit-cache
-    paths:
-      - ${XDG_CACHE_HOME}/pre-commit
-      - ${XDG_CACHE_HOME}/pip
-  rules:
-    - exists:
-      - .pre-commit-config.yaml
-
-tests:
-  stage: test
-  image: python:${PYTHON}
-  parallel:
-    matrix:
-      - PYTHON: ["3.9", "3.10"]
-        TAG: ["docker"]
-  tags:
-    - bob
-    - ${TAG}
-  needs:
-    - job: quality
-      optional: true
-  before_script:
-    # get pip-constraints.txt from distribution
-    - python3 -m venv _citools
-    - source _citools/bin/activate
-    - pip install "${CITOOLS}"
-    - citool pip-constraints "constraints.txt"
-    - deactivate
-    # normal test procedure
-    - python3 -m venv venv
-    - source venv/bin/activate
-    - pip install -c constraints.txt '.[test]' pytest-cov coverage
-  script:
-    - pytest -sv --cov-report "html:html/coverage" --cov-report "xml:coverage.xml" --junitxml "junit-coverage.xml"
-  coverage: '/(?:TOTAL|total|Total).*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
-  cache:
-    key: test-cache-${TAG}-${PYTHON}
-    paths:
-      - ${XDG_CACHE_HOME}/pip
-  artifacts:
-    paths:
-      - html
-    reports:
-      junit: junit-coverage.xml
-      coverage_report:
-        coverage_format: cobertura
-        path: coverage.xml
-
-documentation:
-  stage: doc
-  rules:
-    - exists:
-      - doc/conf.py
-  needs:
-    - job: quality
-      optional: true
-  cache:
-    key: doc-cache
-    paths:
-      - ${XDG_CACHE_HOME}/pip
-  before_script:
-    # get pip-constraints.txt from distribution
-    - python3 -m venv _citools
-    - source _citools/bin/activate
-    - pip install "${CITOOLS}"
-    - citool pip-constraints "constraints.txt"
-    - deactivate
-    # normal doc-building procedure
-    - python3 -m venv venv
-    - source venv/bin/activate
-    - pip install -c constraints.txt '.[doc]' sphinx
-  script:
-    - sphinx-build -aEW doc html/sphinx
-    - sphinx-build -aEb doctest doc html/doctest
-  artifacts:
-    paths:
-      - html
-
-python-package:
-  stage: dist
-  cache:
-    key: packaging-cache
-    paths:
-      - ${XDG_CACHE_HOME}/pip
-  needs:
-    - tests
-  before_script:
-    - python3 -m venv venv
-    - source venv/bin/activate
-    - pip install build twine
-  script:
-    - python -m build
-    - twine check dist/*
-  artifacts:
-    paths:
-      - dist
-
-conda-package:
-  stage: dist
-  # make sure we use the same image as conda-forge:
-  # https://github.com/conda-forge/conda-forge-pinning-feedstock/blob/main/recipe/conda_build_config.yaml
-  image: quay.io/condaforge/linux-anvil-cos7-x86_64
-  variables:
-    CONDA_OVERRIDE_CUDA: "11.6"
-  needs:
-    - tests
-  rules:
-    - exists:
-      - conda/meta.yaml
-  before_script:
-    - pip install "${CITOOLS}"
-    - rm -f /home/conda/.condarc
-    - citool conda-config --group "${CI_PROJECT_NAMESPACE}" --visibility "${CI_PROJECT_VISIBILITY}" --tag "${CI_COMMIT_TAG}" /opt/conda/condarc
-    - mamba update -n base --all
-    - eval "$(/opt/conda/bin/conda shell.bash hook)"
-    - PACKAGE_NAME=$(python setup.py --name 2>/dev/null)
-    - PACKAGE_VERSION=$(python setup.py --version 2>/dev/null)
-    - export BOB_BUILD_NUMBER=$(citool next-build --group "${CI_PROJECT_NAMESPACE}" --visibility "${CI_PROJECT_VISIBILITY}" --tag "${CI_COMMIT_TAG}" --name "${PACKAGE_NAME}" --version "${PACKAGE_VERSION}" conda-package-matches.txt)
-  script:
-    - mkdir dist
-    - echo "-> ${PACKAGE_NAME}-${PACKAGE_VERSION} build-number is ${BOB_BUILD_NUMBER}"
-    - citool conda-constraints conda/conda_build_config.yaml conda/recipe_append.yaml
-    - conda info
-    - conda mambabuild --output-folder=$(pwd)/dist conda
-  artifacts:
-    paths:
-      - dist
-      - conda-package-matches.txt
-
-local-pypi:
-  stage: deploy
-  needs:
-    - python-package
-  cache:
-    key: pypi-cache
-    paths:
-      - ${XDG_CACHE_HOME}/pip
-  rules:
-    # conditions:
-    # - only on the main branch
-    # - public or private
-    # - for tags or not
-    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
-  variables:
-    TWINE_USERNAME: "gitlab-ci-token"
-    TWINE_PASSWORD: "${CI_JOB_TOKEN}"
-  before_script:
-    - python3 -m venv venv
-    - source venv/bin/activate
-    - pip install "${CITOOLS}" twine
-    - PACKAGE_NAME=$(python setup.py --name 2>/dev/null)
-    - PACKAGE_VERSION=$(python setup.py --version 2>/dev/null)
-  script:
-    # only accept to replace version if not a tag
-    - test -z "${CI_COMMIT_TAG}" && citool deregister --git-url "${CI_SERVER_URL}" --token "${PYPI_PACKAGE_REGISTRY_TOKEN}" --project "${CI_PROJECT_ID}" --name "${PACKAGE_NAME}" --version "${PACKAGE_VERSION}"
-    - twine upload --repository-url "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi" dist/*
-
-pypi:
-  extends: local-pypi
-  needs:
-    # only uploads to official PyPI if local PyPI upload suceeded as well
-    - local-pypi
-  rules:
-    # conditions:
-    # - only on the main branch
-    # - only for public packages
-    # - only for tags in PEP-440 style
-    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PROJECT_VISIBILITY == "public" && $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+([abc]\d*)?$/
-  variables:
-    TWINE_USERNAME: "${PYPIUSER}"
-    TWINE_PASSWORD: "${PYPIPASS}"
-  script:
-    - twine upload dist/*
-
-local-docs:
-  stage: deploy
-  needs:
-    - tests
-    - job: documentation
-      optional: true
-  rules:
-    - if: ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH)
-  cache:
-    key: deploy-docs-cache
-    paths:
-      - ${XDG_CACHE_HOME}/pip
-  before_script:
-    - python3 -m venv venv
-    - source venv/bin/activate
-    - pip install "${CITOOLS}"
-  script:
-    # uses DOCUSER/DOCPASS environment variables
-    - citool deploy-docs --package "${CI_PROJECT_PATH}" --visibility "${CI_PROJECT_VISIBILITY}" --branch "${CI_COMMIT_REF_NAME}" --tag "${CI_COMMIT_TAG}" html
-
-conda-deploy:
-  stage: deploy
-  needs:
-    - conda-package
-  rules:
-    - if: ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH)
-  cache:
-    key: deploy-conda-cache
-    paths:
-      - ${XDG_CACHE_HOME}/pip
-  before_script:
-    - python3 -m venv venv
-    - source venv/bin/activate
-    - pip install "${CITOOLS}"
-  script:
-    # uses DOCUSER/DOCPASS environment variables
-    - citool deploy-conda --visibility "${CI_PROJECT_VISIBILITY}" --tag "${CI_COMMIT_TAG}" dist/*/*.conda
+include:
+  - project: bob/citools
+    ref: master
+    file: /src/citools/data/python.yml