diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1650b82a9abe25cb4a8175edb57a6f2af33d887d..20272ac5a1a967adf4f32aa65d6778176d3cf38b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,8 +1,7 @@
-include:
-- local: "{{cookiecutter.project_slug}}/.gitlab-ci.yml"
-
-variables:
-  GIT_SUBMODULE_STRATEGY: recursive
+stages:
+  - prepare
+  - build
+  - test
 
 trigger_prepare:
   stage: prepare
@@ -10,53 +9,42 @@ trigger_prepare:
     strategy: depend
     include: "{{cookiecutter.project_slug}}/.prepare.gitlab-ci.yml"
 
-default:
+# Generate template instance in my_awesome_app directory
+build-template:
+  stage: build
+  image: $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG
   # Bootstrap Cookiecutter template to test provided ci pipeline template
-  before_script:
+  script:
     - python --version # For debugging
-    - git config --global user.name "unit test"
-    - git config --global user.email "info@astron.nl"
     - cookiecutter --no-input --overwrite-if-exists --output-dir . .
     - cd my_awesome_app
-
-# Override semgrep-sast before script
-sast:
-  before_script:
-    - python --version # For debugging
-
-# Override unit test before script
-.run_unit_test_version_base:
-  before_script:
-    - pip install cookiecutter
-    - !reference [default, before_script]
-    - python --version # For debugging
-    - python -m pip install --upgrade pip
-    - pip install --upgrade tox twine
-
-# Override artifact directories
-package_docs:
-  stage: package
-  artifacts:
-    expire_in: 1w
-    paths:
-      - my_awesome_app/docs/build/*
-
-# override package files before script
-package_files:
-  before_script:
-    - pip install cookiecutter
-    - !reference [default, before_script]
+    - git init
+    - git config user.email "ci-runner@example.com"
+    - git config user.name "CI Runner"
+    - source ./setup.sh
+    - ls -lah
+    - tox --version
+    - pip install --upgrade tox
+    - tox -e fix
+    - rm -r .venv
+    - rm -r .tox
+  # cannot use needs, for artifacts on child pipeline so must regenerate template!
   artifacts:
-    expire_in: 1w
     paths:
-      - my_awesome_app/dist/*
-
-# Override artifact directories
-run_unit_tests_coverage:
-  artifacts:
-    reports:
-      coverage_report:
-        coverage_format: cobertura
-        path: my_awesome_app/coverage.xml
-    paths:
-      - my_awesome_app/htmlcov/*
+      - my_awesome_app/*
+      - project.gitlab-ci.yml
+
+# Spawn pipeline using the gitlab-ci.yml from generated template instance
+# use project.gitlab.ci.yml for necessary job overrides from this template instance
+# (due to changes in directories and paths etc)
+project-pipeline:
+  stage: test
+  trigger:
+    strategy: depend
+    include:
+      - artifact: my_awesome_app/.gitlab-ci.yml
+        job: build-template
+      - artifact: project.gitlab-ci.yml
+        job: build-template
+  variables:
+    PARENT_PIPELINE_ID: $CI_PIPELINE_ID
diff --git a/project.gitlab-ci.yml b/project.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..663b7b530b0b476902c3ffb0e18674d7bc16da2c
--- /dev/null
+++ b/project.gitlab-ci.yml
@@ -0,0 +1,122 @@
+
+# This file overrides all the jobs defined in {{cookiecutter.project_slug}}/.gitlab.ci-yml
+# this is to ensure they depend on the template installation artifact of the root
+# .gitlab-ci.yml from job `build-template`
+# The generated gitlab-ci.yml from this `build-template` job is used for the actual
+# trigger include to prevent including jobs that still contain template arguments
+
+
+trigger_prepare:
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "parent_pipeline"
+      when: never
+
+default:
+  # Bootstrap Cookiecutter template to test provided ci pipeline template
+  before_script:
+    - cd my_awesome_app
+
+run_lint:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+
+sast:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+
+dependency_scanning:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+
+secret_detection:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+
+.run_unit_test_version_base:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+
+# Run all unit tests for Python versions except the base image
+run_unit_tests:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+
+# Run code coverage on the base image thus also performing unit tests
+run_unit_tests_coverage:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+  artifacts:
+    reports:
+      coverage_report:
+        coverage_format: cobertura
+        path: my_awesome_app/coverage.xml
+    paths:
+      - my_awesome_app/htmlcov/*
+
+package_files:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+  artifacts:
+    expire_in: 1w
+    paths:
+      - my_awesome_app/dist/*
+
+package_docs:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+  artifacts:
+    expire_in: 1w
+    paths:
+      - my_awesome_app/docs/build/*
+
+#docker_build:
+#  needs:
+#    - pipeline: $PARENT_PIPELINE_ID
+#      job: build-template
+#    - package_files
+#  before_script:
+#    - cd my_awesome_app
+
+run_integration_tests:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+    - package_files
+
+publish_on_gitlab:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+    - package_files
+
+publish_on_test_pypi:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+    - package_files
+
+publish_on_pypi:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+    - package_files
+
+publish_to_readthedocs:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template
+    - package_docs
+
+release_job:
+  needs:
+    - pipeline: $PARENT_PIPELINE_ID
+      job: build-template