diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..24e6cbf1898ff6c5f1fd5827ebf03ee4eee1a8fd
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,31 @@
+image: python:3.9-slim-buster
+
+stages:
+  - qc
+  - test
+
+qc_1:
+  stage: qc
+
+  before_script:
+    - pip install -r requirements.txt
+    - pip install -r requirements_dev.txt
+    - pip install -e .
+
+  script:
+    - flake8 src/ setup.py
+    - coverage run --source src/ -m pytest
+    - coverage report --fail-under=100
+    - mypy src/
+
+test_1:
+  stage: test
+
+  before_script:
+    - pip install -r requirements.txt
+    - pip install -r requirements_dev.txt
+    - pip install -e .
+
+  script:
+    - python -m pytest
+
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/requirements_dev.txt b/requirements_dev.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a382a353782fbec24777b5fb3e168b3bb29865de
--- /dev/null
+++ b/requirements_dev.txt
@@ -0,0 +1,5 @@
+flake8
+flake8-docstrings
+pytest
+mypy
+coverage
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..1d48b941a4af24a65daf41637c08ab7cb0e4950c
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,3 @@
+[flake8]
+max-line-length = 120
+docstring-convention = google
\ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..85e5c86540e4b618885eda720f9a39c5616cfe6a
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,16 @@
+"""Setup the package."""
+
+from setuptools import setup, find_packages
+import src
+
+
+setup(
+    name='src',
+    author='Zavolan Lab, Biozentrum, University of Basel',
+    url='https://git.scicore.unibas.ch/zavolan_group/pipelines/scrna-seq-simulation',
+    license='MIT',
+    version=src.__version__,
+    install_requires=[],
+    entrypoints={},
+    packages=find_packages()
+)
diff --git a/src/__init__.py b/src/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..46fb5934542d5cc3171477c1b3bc135ada4df0ab
--- /dev/null
+++ b/src/__init__.py
@@ -0,0 +1,3 @@
+"""Placeholder package."""
+
+__version__ = '0.0.0'
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..024d7a52e7545aee1b4d97fd409e79a58f22657a
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1 @@
+"""Tests for the package src."""
diff --git a/tests/test_dummy.py b/tests/test_dummy.py
new file mode 100644
index 0000000000000000000000000000000000000000..73a51173c54f6a3c3b35cccb7e8d3b13c313ba48
--- /dev/null
+++ b/tests/test_dummy.py
@@ -0,0 +1,10 @@
+"""Placeholder test for pipeline."""
+
+import src
+import re
+
+
+def test_version():
+    """Assert that version matches semantic versioning format."""
+
+    assert re.match(r'\d\.\d\.\d', src.__version__)