diff --git a/templates/gitlab-ci-python.yml b/templates/gitlab-ci-python.yml
index 1c81b51e46b363fc67afec5f1bbdd6e23317ce00..38d089ccc5ccfc1953b687700fef4fe8ec03a8d2 100644
--- a/templates/gitlab-ci-python.yml
+++ b/templates/gitlab-ci-python.yml
@@ -211,14 +211,6 @@ variables:
   # variabilized tracking image
   TBC_TRACKING_IMAGE: "registry.gitlab.com/to-be-continuous/tools/tracking:master"
 
-  # Change pip's cache directory to be inside the project directory since we can
-  # only cache local items.
-  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
-  # Poetry support: force virtualenv not in project dir & use local cache dir
-  POETRY_CACHE_DIR: "$CI_PROJECT_DIR/.cache/poetry"
-  POETRY_VIRTUALENVS_IN_PROJECT: "false"
-  PIPENV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pipenv"
-
   # PYTHON_IMAGE: "registry.hub.docker.com/library/python:3"
   PYTHON_IMAGE: $[[ inputs.image ]]
   # Default Python project root directory
@@ -819,14 +811,18 @@ stages:
   services:
     - name: "$TBC_TRACKING_IMAGE"
       command: ["--service", "python", "6.10.0"]
-  # Cache downloaded dependencies and plugins between builds.
-  # To keep cache across branches add 'key: "$CI_JOB_NAME"'
+  variables:
+    # set local cache dir; most Python tools honour XDG specs
+    XDG_CACHE_HOME: "$CI_PROJECT_DIR/.cache"
+    PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
+    POETRY_CACHE_DIR: "$CI_PROJECT_DIR/.cache/poetry"
+    PIPENV_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pipenv"
+    POETRY_VIRTUALENVS_IN_PROJECT: "false"
   cache:
     key: "$CI_COMMIT_REF_SLUG-python"
+    when: always
     paths:
-      - ${PIP_CACHE_DIR}
-      - ${POETRY_CACHE_DIR}
-      - ${PIPENV_CACHE_DIR}
+      - .cache
   before_script:
     - !reference [.python-scripts]
     - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}"