diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000000000000000000000000000000000..16beae29cc7f31303c709b4981421f395512d84b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,148 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+max_line_length = 120
+tab_width = 4
+ij_continuation_indent_size = 8
+ij_formatter_off_tag = @formatter:off
+ij_formatter_on_tag = @formatter:on
+ij_formatter_tags_enabled = false
+ij_smart_tabs = false
+ij_visual_guides = none
+ij_wrap_on_typing = false
+
+[{*.bash,*.sh,*.zsh}]
+indent_size = 2
+tab_width = 2
+ij_shell_binary_ops_start_line = false
+ij_shell_keep_column_alignment_padding = false
+ij_shell_minify_program = false
+ij_shell_redirect_followed_by_space = false
+ij_shell_switch_cases_indented = false
+ij_shell_use_unix_line_separator = true
+
+[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config}]
+indent_size = 2
+ij_json_array_wrapping = split_into_lines
+ij_json_keep_blank_lines_in_code = 0
+ij_json_keep_indents_on_empty_lines = false
+ij_json_keep_line_breaks = true
+ij_json_keep_trailing_comma = false
+ij_json_object_wrapping = split_into_lines
+ij_json_property_alignment = do_not_align
+ij_json_space_after_colon = true
+ij_json_space_after_comma = true
+ij_json_space_before_colon = false
+ij_json_space_before_comma = false
+ij_json_spaces_within_braces = false
+ij_json_spaces_within_brackets = false
+ij_json_wrap_long_lines = false
+
+[{*.markdown,*.md}]
+ij_markdown_force_one_space_after_blockquote_symbol = true
+ij_markdown_force_one_space_after_header_symbol = true
+ij_markdown_force_one_space_after_list_bullet = true
+ij_markdown_force_one_space_between_words = true
+ij_markdown_insert_quote_arrows_on_wrap = true
+ij_markdown_keep_indents_on_empty_lines = false
+ij_markdown_keep_line_breaks_inside_text_blocks = true
+ij_markdown_max_lines_around_block_elements = 1
+ij_markdown_max_lines_around_header = 1
+ij_markdown_max_lines_between_paragraphs = 1
+ij_markdown_min_lines_around_block_elements = 1
+ij_markdown_min_lines_around_header = 1
+ij_markdown_min_lines_between_paragraphs = 1
+ij_markdown_wrap_text_if_long = true
+ij_markdown_wrap_text_inside_blockquotes = true
+
+[{*.py,*.pyw}]
+max_line_length = 88
+ij_python_align_collections_and_comprehensions = true
+ij_python_align_multiline_imports = true
+ij_python_align_multiline_parameters = true
+ij_python_align_multiline_parameters_in_calls = false
+ij_python_blank_line_at_file_end = true
+ij_python_blank_lines_after_imports = 1
+ij_python_blank_lines_after_local_imports = 0
+ij_python_blank_lines_around_class = 1
+ij_python_blank_lines_around_method = 1
+ij_python_blank_lines_around_top_level_classes_functions = 2
+ij_python_blank_lines_before_first_method = 0
+ij_python_call_parameters_new_line_after_left_paren = true
+ij_python_call_parameters_right_paren_on_new_line = true
+ij_python_call_parameters_wrap = normal
+ij_python_dict_alignment = 2
+ij_python_dict_new_line_after_left_brace = true
+ij_python_dict_new_line_before_right_brace = true
+ij_python_dict_wrapping = 1
+ij_python_from_import_new_line_after_left_parenthesis = true
+ij_python_from_import_new_line_before_right_parenthesis = true
+ij_python_from_import_parentheses_force_if_multiline = true
+ij_python_from_import_trailing_comma_if_multiline = false
+ij_python_from_import_wrapping = 1
+ij_python_hang_closing_brackets = false
+ij_python_keep_blank_lines_in_code = 1
+ij_python_keep_blank_lines_in_declarations = 1
+ij_python_keep_indents_on_empty_lines = false
+ij_python_keep_line_breaks = true
+ij_python_method_parameters_new_line_after_left_paren = true
+ij_python_method_parameters_right_paren_on_new_line = true
+ij_python_method_parameters_wrap = normal
+ij_python_new_line_after_colon = true
+ij_python_new_line_after_colon_multi_clause = true
+ij_python_optimize_imports_always_split_from_imports = false
+ij_python_optimize_imports_case_insensitive_order = false
+ij_python_optimize_imports_join_from_imports_with_same_source = false
+ij_python_optimize_imports_sort_by_type_first = true
+ij_python_optimize_imports_sort_imports = true
+ij_python_optimize_imports_sort_names_in_from_imports = false
+ij_python_space_after_comma = true
+ij_python_space_after_number_sign = true
+ij_python_space_after_py_colon = true
+ij_python_space_before_backslash = true
+ij_python_space_before_comma = false
+ij_python_space_before_for_semicolon = false
+ij_python_space_before_lbracket = false
+ij_python_space_before_method_call_parentheses = false
+ij_python_space_before_method_parentheses = false
+ij_python_space_before_number_sign = true
+ij_python_space_before_py_colon = false
+ij_python_space_within_empty_method_call_parentheses = false
+ij_python_space_within_empty_method_parentheses = false
+ij_python_spaces_around_additive_operators = true
+ij_python_spaces_around_assignment_operators = true
+ij_python_spaces_around_bitwise_operators = true
+ij_python_spaces_around_eq_in_keyword_argument = false
+ij_python_spaces_around_eq_in_named_parameter = false
+ij_python_spaces_around_equality_operators = true
+ij_python_spaces_around_multiplicative_operators = true
+ij_python_spaces_around_power_operator = false
+ij_python_spaces_around_relational_operators = true
+ij_python_spaces_around_shift_operators = true
+ij_python_spaces_within_braces = false
+ij_python_spaces_within_brackets = false
+ij_python_spaces_within_method_call_parentheses = false
+ij_python_spaces_within_method_parentheses = false
+ij_python_use_continuation_indent_for_arguments = true
+ij_python_use_continuation_indent_for_collection_and_comprehensions = false
+ij_python_use_continuation_indent_for_parameters = true
+ij_python_wrap_long_lines = false
+
+[{*.yaml,*.yml}]
+indent_size = 2
+ij_yaml_align_values_properties = do_not_align
+ij_yaml_autoinsert_sequence_marker = true
+ij_yaml_block_mapping_on_new_line = false
+ij_yaml_indent_sequence_value = true
+ij_yaml_keep_indents_on_empty_lines = false
+ij_yaml_keep_line_breaks = true
+ij_yaml_sequence_on_new_line = false
+ij_yaml_space_before_colon = false
+ij_yaml_spaces_within_braces = true
+ij_yaml_spaces_within_brackets = true
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..499f958b2b1d3bfa2cb18834fdd25fca3716f884
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+dist/*
+*.egg-info
+*.pyc
+.tox
+
+.coverage
+coverage.xml
+htmlcov/*
+build
+dist
+
+# Documentation
+docs/source/source_documentation
+!docs/source/source_documentation/index.rst
+docs/build
+
+# Setuptools SCM
+sid/_version.py
+
+# IDE configuration
+.vscode
+.idea
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c7c6e90fb2a4ce0a47ade68c4f79b2855a551579
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,227 @@
+default:
+  image:
+    name: $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG
+    pull_policy: always
+  before_script:
+    - python --version # For debugging
+  cache:
+    paths:
+      - .cache/pip
+      # Do not cache .tox, to recreate virtualenvs for every step
+
+stages:
+  - prepare
+  - lint
+  # check if this needs to be a separate step
+  # - build_extensions
+  - test
+  - package
+  - images
+  - integration
+  - publish # publish instead of deploy
+
+# Caching of dependencies to speed up builds
+variables:
+  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
+
+include:
+  - template: Security/SAST.gitlab-ci.yml
+  - template: Security/Dependency-Scanning.gitlab-ci.yml
+  - template: Security/Secret-Detection.gitlab-ci.yml
+
+# Prepare image to run ci on
+trigger_prepare:
+  stage: prepare
+  trigger:
+    strategy: depend
+    include: .prepare.gitlab-ci.yml
+
+run_black:
+  stage: lint
+  script:
+    - tox -e black
+  allow_failure: true
+
+run_flake8:
+  stage: lint
+  script:
+    - tox -e pep8
+  allow_failure: true
+
+run_pylint:
+  stage: lint
+  script:
+    - tox -e pylint
+  allow_failure: true
+
+# build_extensions:
+#   stage: build_extensions
+#   script:
+#     - echo "build fortran/c/cpp extension source code"
+
+sast:
+  variables:
+    SAST_EXCLUDED_ANALYZERS: brakeman, flawfinder, kubesec, nodejs-scan, phpcs-security-audit,
+      pmd-apex, security-code-scan, sobelow, spotbugs
+  stage: test
+
+dependency_scanning:
+  # override default before_script, job won't have Python available
+  before_script:
+    - uname
+
+secret_detection:
+  # override default before_script, job won't have Python available
+  before_script:
+    - uname
+
+# Basic setup for all Python versions for which we don't have a base image
+.run_unit_test_version_base:
+  before_script:
+    - python --version # For debugging
+    - python -m pip install --upgrade pip
+    - python -m pip install --upgrade tox twine
+
+# Run all unit tests for Python versions except the base image
+run_unit_tests:
+  extends: .run_unit_test_version_base
+  stage: test
+  image: python:3.${PY_VERSION}
+  script:
+    - tox -e py3${PY_VERSION}
+  parallel:
+    matrix: # use the matrix for testing
+      - PY_VERSION: [8, 9, 10, 11]
+
+# Run code coverage on the base image thus also performing unit tests
+run_unit_tests_coverage:
+  stage: test
+  script:
+   - tox -e coverage
+  coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
+  artifacts:
+    reports:
+      coverage_report:
+        coverage_format: cobertura
+        path: coverage.xml
+    paths:
+      - htmlcov/*
+
+package_files:
+  stage: package
+  artifacts:
+    expire_in: 1w
+    paths:
+      - dist/*
+  script:
+    - tox -e build
+
+package_docs:
+  stage: package
+  artifacts:
+    expire_in: 1w
+    paths:
+      - docs/build/*
+  script:
+    - tox -e docs
+
+docker_build:
+  stage: images
+  image: docker:latest
+  needs:
+    - package_files
+  tags:
+    - dind
+  before_script: []
+  script:
+    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+    - docker build -f docker/sid/Dockerfile . --build-arg BUILD_ENV=copy --tag $CI_REGISTRY_IMAGE/sid:$CI_COMMIT_REF_SLUG
+    # enable this push line once you have configured docker registry cleanup policy
+    # - docker push $CI_REGISTRY_IMAGE/sid:$CI_COMMIT_REF_SLUG
+
+run_integration_tests:
+  stage: integration
+  allow_failure: true
+  needs:
+    - package_files
+  script:
+    - echo "make sure to move out of source dir"
+    - echo "install package from filesystem (or use the artefact)"
+    - echo "run against foreign systems (e.g. databases, cwl etc.)"
+    - exit 1
+
+publish_on_gitlab:
+  stage: publish
+  environment: gitlab
+  needs:
+    - package_files
+  when: manual
+  rules:
+    - if: $CI_COMMIT_TAG
+  script:
+    - echo "run twine for gitlab"
+    - |
+      TWINE_PASSWORD=${CI_JOB_TOKEN} \
+      TWINE_USERNAME=gitlab-ci-token \
+      python -m twine upload \
+      --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/*
+
+publish_on_test_pypi:
+  stage: publish
+  environment: pypi-test
+  needs:
+    - package_files
+  when: manual
+  rules:
+    - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"'
+  script:
+    - echo "run twine for test pypi"
+    # - |
+    #   TWINE_PASSWORD=${PIPY_TOKEN} \
+    #   TWINE_USERNAME=${PIPY_USERNAME} \
+    # TODO: replace URL with a pipy URL
+    #   python -m twine upload \
+    #   --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/*
+    - exit 1
+
+publish_on_pypi:
+  stage: publish
+  environment: pypi
+  needs:
+    - package_files
+  when: manual
+  rules:
+    - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"'
+  script:
+    - echo "run twine for pypi"
+    # - |
+    #   TWINE_PASSWORD=${PIPY_TOKEN} \
+    #   TWINE_USERNAME=${PIPY_USERNAME} \
+    # TODO: replace URL with a pipy URL
+    #   python -m twine upload \
+    #   --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/*
+    - exit 1
+
+publish_to_readthedocs:
+  stage: publish
+  allow_failure: true
+  environment: readthedocs
+  needs:
+    - package_docs
+  when: manual
+  rules:
+    - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"'
+  script:
+    - echo "scp docs/* ???"
+    - exit 1
+
+release_job:
+  stage: publish
+  image: registry.gitlab.com/gitlab-org/release-cli:latest
+  rules:
+    - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"'
+  script:
+    - echo "running release_job"
+  release:
+    tag_name: '$CI_COMMIT_TAG'
+    description: '$CI_COMMIT_TAG - $CI_COMMIT_TAG_MESSAGE'
diff --git a/.prepare.gitlab-ci.yml b/.prepare.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3e48a271564faec892e42aab9f947d946ecc4d7b
--- /dev/null
+++ b/.prepare.gitlab-ci.yml
@@ -0,0 +1,23 @@
+stages:
+  - build
+
+build_ci_runner_image:
+  stage: build
+  image: docker
+  tags:
+    - dind
+  script:
+    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+    - |
+      if docker pull $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG; then
+        docker build --cache-from $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG --tag $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG docker/ci-runner
+      else
+        docker pull $CI_REGISTRY_IMAGE/ci-build-runner:latest || true
+        docker build --cache-from $CI_REGISTRY_IMAGE/ci-build-runner:latest --tag $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG docker/ci-runner
+      fi
+    - docker push $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG  # push the image
+    - |
+      if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
+        docker image tag $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG $CI_REGISTRY_IMAGE/ci-build-runner:latest
+        docker push $CI_REGISTRY_IMAGE/ci-build-runner:latest
+      fi
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000000000000000000000000000000000000..c4a3399ac9b36be786467e020c84f95e09db0606
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,5 @@
+include LICENSE
+include README.md
+
+recursive-include docs *
+recursive-exclude tests *
diff --git a/docker/ci-runner/Dockerfile b/docker/ci-runner/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..6cb46437656aad64d8292c0a10f6edaffffba8e3
--- /dev/null
+++ b/docker/ci-runner/Dockerfile
@@ -0,0 +1,4 @@
+FROM python:3.12
+
+RUN python -m pip install --upgrade pip
+RUN python -m pip install --upgrade tox twine
diff --git a/docker/sid/Dockerfile b/docker/sid/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..ceea7e721fc3acaa124184e709986e04dbd9a3dd
--- /dev/null
+++ b/docker/sid/Dockerfile
@@ -0,0 +1,18 @@
+ARG BUILD_ENV=no_copy
+
+FROM python:3.11 AS build_no_copy
+ADD ../../requirements.txt .
+COPY ../.. /work
+RUN rm -r /work/dist | true
+RUN python -m pip install --user tox
+WORKDIR /work
+RUN python -m tox -e build
+
+FROM python:3.11 AS build_copy
+COPY dist /work/dist
+
+FROM build_${BUILD_ENV} AS build
+
+FROM python:3.11-slim
+COPY --from=build /work/dist /dist
+RUN python -m pip install /dist/*.whl
diff --git a/docs/cleanup.py b/docs/cleanup.py
new file mode 100644
index 0000000000000000000000000000000000000000..3a4508d859234544bea35b1008e3c8e4f73d7cc0
--- /dev/null
+++ b/docs/cleanup.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+
+#  Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy)
+#  SPDX-License-Identifier: Apache-2.0
+
+import os
+
+file_dir = os.path.dirname(os.path.realpath(__file__))
+
+clean_dir = os.path.join(file_dir, "source", "source_documentation")
+print(f"Cleaning.. {clean_dir}/*")
+
+if not os.path.exists(clean_dir):
+    exit()
+
+for file_name in os.listdir(clean_dir):
+    file = os.path.join(clean_dir, file_name)
+    
+    if file_name == "index.rst":
+        continue
+
+    print(f"Removing.. {file}")
+    os.remove(file)
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3c6e46c6db7ddaf65e47cfa22c9ec0b914f7fd38
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,5 @@
+sphinx!=1.6.6,!=1.6.7,>=1.6.5 # BSD
+sphinx-rtd-theme>=0.4.3 #MIT
+sphinxcontrib-apidoc>=0.3.0 #BSD
+myst-parser>=2.0 # MIT
+docutils>=0.17 # BSD
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 0000000000000000000000000000000000000000..049edbb63d22442d7c9513ef3e7bb72d93f8c48f
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,93 @@
+#  Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy)
+#  SPDX-License-Identifier: Apache-2.0
+
+import os
+
+from sid._version import __version__
+
+# -- General configuration ----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+    "sphinx.ext.autodoc",
+    "sphinx.ext.viewcode",
+    "sphinxcontrib.apidoc",
+    "sphinx_rtd_theme",
+    "myst_parser"
+]
+
+# Assumes tox is used to call sphinx-build
+project_root_directory = os.getcwd()
+
+apidoc_module_dir = "../../sid"
+apidoc_output_dir = "source_documentation"
+apidoc_excluded_paths = []
+apidoc_separate_modules = True
+apidoc_toc_file = False
+# This should include private methods but does not work
+# https://github.com/sphinx-contrib/apidoc/issues/14
+apidoc_extra_args = ["--private"]
+
+# The suffix of source filenames.
+source_suffix = [".rst"]
+
+# The master toctree document.
+master_doc = "index"
+
+# General information about the project.
+project = "sid"
+copyright = "2023, ASTRON"
+
+# openstackdocstheme options
+repository_name = "https://git.astron.nl/lofar2.0/sid"
+bug_project = "none"
+bug_tag = ""
+html_last_updated_fmt = "%Y-%m-%d %H:%M"
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+version = __version__
+
+modindex_common_prefix = ["sid."]
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+add_module_names = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = "sphinx"
+
+# -- Options for HTML output --------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+# html_theme_path = ["."]
+html_theme = "sphinx_rtd_theme"
+html_static_path = ["static"]
+html_css_files = [
+    "css/custom.css",
+]
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = "%sdoc" % project
+
+# Conf.py variables exported to sphinx rst files access using |NAME|
+variables_to_export = [
+    "project",
+    "copyright",
+    "version",
+]
+
+# Write to rst_epilog to export `variables_to_export` extract using `locals()`
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-rst_epilog
+frozen_locals = dict(locals())
+rst_epilog = "\n".join(
+    map(
+        lambda x: f".. |{x}| replace:: {frozen_locals[x]}",  # noqa: F821
+        variables_to_export,
+    )
+)
+# Pep is not able to determine that frozen_locals always exists so noqa
+del frozen_locals
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..c786f976ad074d142a3edeae6f54a4f1fb8a3c64
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,16 @@
+====================================================
+Welcome to the documentation of sid
+====================================================
+
+..
+    To define more variables see rst_epilog generation in conf.py
+
+Documentation for version: |version|
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   readme
+   source_documentation/index
diff --git a/docs/source/readme.rst b/docs/source/readme.rst
new file mode 100644
index 0000000000000000000000000000000000000000..87c96deef60fc04b35a8b9b9cca2f72b7e64e70c
--- /dev/null
+++ b/docs/source/readme.rst
@@ -0,0 +1,2 @@
+.. include:: ../../README.md
+   :parser: myst_parser.sphinx_
diff --git a/docs/source/static/css/custom.css b/docs/source/static/css/custom.css
new file mode 100644
index 0000000000000000000000000000000000000000..3ea8a2fc0c9c1ecb2b318cbc32edf90d2940c38d
--- /dev/null
+++ b/docs/source/static/css/custom.css
@@ -0,0 +1,14 @@
+.orange { color: #c65d09; }
+
+.green { color: #5dc609; }
+
+.yellow { color: #c6c609; }
+
+.bolditalic {
+  font-weight: bold;
+  font-style: italic;
+}
+
+.rst-content code, .rst-content tt, code {
+  white-space: break-spaces;
+}
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000000000000000000000000000000000000..f325d08c503701ce9cb8a88ad89797bded24c23d
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,13 @@
+[build-system]
+requires = [
+    "setuptools>=62.6",
+    "setuptools_scm[toml]>=8.0",
+    "wheel"
+]
+build-backend = "setuptools.build_meta"
+
+[tool.setuptools_scm]
+version_file = "sid/_version.py"
+
+[tool.pylint]
+ignore = "_version.py"
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8f81bc285d0db9ea0945151fed0cd47eec4ee6a2
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+importlib-metadata>=0.12, <5.0;python_version<"3.8"
+numpy
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..43649afca400f4cceec1e6e66ddae9f8512fe8aa
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,37 @@
+[metadata]
+name = sid
+description = Software interface description
+long_description = file: README.md
+long_description_content_type = text/markdown
+url = https://git.astron.nl/lofar2.0/sid
+license = Apache License 2.0
+classifiers =
+    Development Status :: 3 - Alpha
+    Environment :: Web Environment
+    Intended Audience :: Developers
+    Intended Audience :: Science/Research
+    License :: OSI Approved :: Apache Software License
+    Operating System :: OS Independent
+    Programming Language :: Python
+    Programming Language :: Python :: 3
+    Programming Language :: Python :: 3 :: Only
+    Programming Language :: Python :: 3.8
+    Programming Language :: Python :: 3.9
+    Programming Language :: Python :: 3.10
+    Programming Language :: Python :: 3.11
+    Programming Language :: Python :: 3.12
+    Topic :: Internet :: WWW/HTTP
+    Topic :: Internet :: WWW/HTTP :: Dynamic Content
+    Topic :: Scientific/Engineering
+    Topic :: Scientific/Engineering :: Astronomy
+
+[options]
+include_package_data = true
+packages = find:
+python_requires = >=3.8
+install_requires = file: requirements.txt
+
+[flake8]
+max-line-length = 88
+extend-ignore = E203
+exclude=.venv,.git,.tox,dist,docs,*lib/python*,*egg,_version.py
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..b908cbe55cb344569d32de1dfc10ca7323828dc5
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,3 @@
+import setuptools
+
+setuptools.setup()
diff --git a/sid/README.md b/sid/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..949233db4b600dfb96b7c5cecb95a4b469ddbfff
--- /dev/null
+++ b/sid/README.md
@@ -0,0 +1,53 @@
+# sid
+
+![Build status](https://git.astron.nl/lofar2.0/sid/badges/main/pipeline.svg)
+![Test coverage](https://git.astron.nl/lofar2.0/sid/badges/main/coverage.svg)
+<!-- ![Latest release](https://git.astron.nl/lofar2.0/sid/badges/main/release.svg) -->
+
+Software interface description
+
+## Installation
+```
+pip install .
+```
+
+## Setup
+
+One time template setup should include configuring the docker registry to regularly cleanup old images of
+the CI/CD pipelines. And you can consider creating protected version tags for software releases:
+
+1. [Cleanup Docker Registry Images](https://git.astron.nl/groups/templates/-/wikis/Cleanup-Docker-Registry-Images)
+2. [Setup Protected Verson Tags](https://git.astron.nl/groups/templates/-/wikis/Setting-up-Protected-Version-Tags)
+
+Once the cleanup policy for docker registry is setup you can uncomment the `docker push` comment in the `.gitlab-ci.yml`
+file from the `docker_build` job. This will allow to download minimal docker images with your Python package installed.
+
+## Usage
+```python
+from sid import cool_module
+
+cool_module.greeter()   # prints "Hello World"
+```
+
+## Contributing
+
+To contribute, please create a feature branch and a "Draft" merge request.
+Upon completion, the merge request should be marked as ready and a reviewer
+should be assigned.
+
+Verify your changes locally and be sure to add tests. Verifying local
+changes is done through `tox`.
+
+```pip install tox```
+
+With tox the same jobs as run on the CI/CD pipeline can be ran. These
+include unit tests and linting.
+
+```tox```
+
+To automatically apply most suggested linting changes execute:
+
+```tox -e format```
+
+## License
+This project is licensed under the Apache License Version 2.0
diff --git a/sid/__init__.py b/sid/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..763e0f6888777a890d7c208e2e39ac283f61f090
--- /dev/null
+++ b/sid/__init__.py
@@ -0,0 +1,4 @@
+#  Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy)
+#  SPDX-License-Identifier: Apache-2.0
+
+""" sid """
diff --git a/sid/cool_module.py b/sid/cool_module.py
new file mode 100644
index 0000000000000000000000000000000000000000..de82c46c186cce3880ff8f56d87ba4406ee195ce
--- /dev/null
+++ b/sid/cool_module.py
@@ -0,0 +1,9 @@
+#  Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy)
+#  SPDX-License-Identifier: Apache-2.0
+
+""" Cool module containing functions, classes and other useful things """
+
+
+def greeter():
+    """Prints a nice message"""
+    print("Hello World!")
diff --git a/tests/.gitkeep b/tests/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/requirements.txt b/tests/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f14d0b907ce977320ba250046dfab52a3101800a
--- /dev/null
+++ b/tests/requirements.txt
@@ -0,0 +1,7 @@
+autopep8 >= 1.7.0 # MIT
+black >= 22.0.0 # MIT
+build >= 0.8.0 # MIT
+flake8 >= 5.0.0 # MIT
+pylint >= 2.15.0 # GPLv2
+pytest >= 7.0.0 # MIT
+pytest-cov >= 3.0.0 # MIT
diff --git a/tests/test_cool_module.py b/tests/test_cool_module.py
new file mode 100644
index 0000000000000000000000000000000000000000..5bf21b15b285b380071c60b06dc1c3abeeb56e47
--- /dev/null
+++ b/tests/test_cool_module.py
@@ -0,0 +1,16 @@
+#  Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy)
+#  SPDX-License-Identifier: Apache-2.0
+
+"""Testing of the Cool Module"""
+from unittest import TestCase
+
+from sid.cool_module import greeter
+
+
+class TestCoolModule(TestCase):
+    """Test Case of the Cool Module"""
+
+    def test_greeter(self):
+        """Testing that the greeter does not crash"""
+        greeter()
+        self.assertEqual(2 + 2, 4)
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000000000000000000000000000000000000..792079e9dfd75fe8cb0adf19c73fd1503c15bc06
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,58 @@
+[tox]
+# Generative environment list to test all supported Python versions
+envlist = py3{9,10,11,12,13},black,pep8,pylint
+min_version = 4.3.3
+requires =
+    tox-ignore-env-name-mismatch >= 0.2.0
+
+[testenv]
+usedevelop = True
+package = wheel
+wheel_build_env = .pkg
+
+setenv =
+    PYTHONWARNINGS=default::DeprecationWarning
+deps =
+    -r{toxinidir}/requirements.txt
+    -r{toxinidir}/tests/requirements.txt
+commands =
+    {envpython} --version
+    {envpython} -m pytest tests/{posargs}
+
+[testenv:coverage]
+commands =
+    {envpython} --version
+    {envpython} -m pytest --cov-report term --cov-report xml --cov-report html --cov=sid tests/{posargs}
+
+# Use generative name and command prefixes to reuse the same virtualenv
+# for all linting jobs.
+[testenv:{pep8,black,pylint,format}]
+usedevelop = False
+package = editable
+envdir = {toxworkdir}/linting
+commands =
+    pep8: {envpython} -m flake8 --version
+    pep8: {envpython} -m flake8 sid tests
+    black: {envpython} -m black --version
+    black: {envpython} -m black --check --diff sid tests
+    pylint: {envpython} -m pylint --version
+    pylint: {envpython} -m pylint sid tests
+    format: {envpython} -m autopep8 -v -aa --in-place --recursive sid
+    format: {envpython} -m autopep8 -v -aa --in-place --recursive tests
+    format: {envpython} -m black -v sid tests
+
+[testenv:docs]
+; unset LC_ALL / LANGUAGE from testenv, would fail sphinx otherwise
+setenv =
+deps =
+    -r{toxinidir}/requirements.txt
+    -r{toxinidir}/docs/requirements.txt
+changedir = {toxinidir}
+commands =
+    {envpython} docs/cleanup.py
+    sphinx-build -b html docs/source docs/build/html
+
+[testenv:build]
+usedevelop = False
+deps = build
+commands = {envpython} -m build