diff --git a/.github/workflows/Dockerfile b/.github/workflows/Dockerfile
deleted file mode 100644
index 547ae88..0000000
--- a/.github/workflows/Dockerfile
+++ /dev/null
@@ -1,9 +0,0 @@
-ARG BASEOS=slim-bullseye
-FROM python:3.11-${BASEOS}
-
-ARG PLATFORM=manylinux
-ENV CI=1
-COPY test /src/test
-COPY wheelhouse/clang*${PLATFORM}*.whl /tmp
-RUN python -m pip install pytest /tmp/*whl \
-    && pytest -vs /src/test
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9d26069..7d01643 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,12 +1,12 @@
 name: Build + Release Wheels
 
 on:
+  push:
+    tags:
+      - 'v?[0-9]+.[0-9]+.[0-9]+'
+      - 'v?[0-9]+.[0-9]+.[0-9]+.[0-9]+'
   workflow_dispatch:
     inputs:
-      use_qemu:
-        description: "Use qemu for builds with targets requiring emulation"
-        required: true
-        default: true
       llvm_version:
         description: "LLVM version to build"
         required: false
@@ -16,72 +16,59 @@ on:
         required: false
         default: "0"
       deploy_to_testpypi:
-        description: "Whether the build should be deployed to test.pypi.org instead regular PyPI"
+        description: "Whether the build should be deployed to test.pypi.org instead of regular PyPI"
         required: true
         default: false
 
-env:
-  USE_QEMU: ${{ github.event.inputs.use_qemu == 'true' }}
-
 jobs:
   build-wheels:
-    name: Build wheels on ${{ matrix.os }} (arch=${{ matrix.arch }})
+    name: "Build wheels on ${{ matrix.os }} :: platform=${{ matrix.platform }} arch=${{ matrix.arch }}"
     runs-on: ${{ matrix.os }}
 
     strategy:
       matrix:
         include:
-          - os: ubuntu-22.04
+          # Linux
+          - os: ubuntu-latest
+            platform: "manylinux"
             arch: "x86_64"
-            use_qemu: false
-            skip: "*manylinux*"
-          - os: ubuntu-22.04
+          - os: ubuntu-latest
+            platform: "musllinux"
             arch: "x86_64"
-            use_qemu: false
-            skip: "*musllinux*"
-          - os: ubuntu-22.04
+          - os: ubuntu-latest
+            platform: "manylinux"
             arch: "i686"
-            use_qemu: false
-            skip: "*manylinux*"
-          - os: ubuntu-22.04
+          - os: ubuntu-latest
+            platform: "musllinux"
             arch: "i686"
-            use_qemu: false
-            skip: "*musllinux*"
-              # These take too long to build on Github
-              #- os: ubuntu-20.04
-              #arch: "aarch64"
-              #use_qemu: true
-              #- os: ubuntu-20.04
-              #arch: "ppc64le"
-              #use_qemu: true
-              #- os: ubuntu-20.04
-              #arch: "s390x"
-              #use_qemu: true
-          - os: windows-2022
+          # Windows
+          - os: windows-latest
+            platform: "win"
             arch: "AMD64"
-            use_qemu: false
-            skip: 
-          - os: windows-2022
+          - os: windows-latest
+            platform: "win"
             arch: "x86"
-            use_qemu: false
-            skip: 
-          - os: macos-12
+          # macOS
+          - os: macos-13
+            platform: "macos"
             arch: "x86_64"
-            use_qemu: false
-            skip: 
-          - os: macos-14
+          - os: macos-latest
+            platform: "macos"
             arch: "arm64"
-            use_qemu: false
-            skip: 
 
     steps:
     - uses: actions/checkout@v4
-      if: (!matrix.use_qemu) || fromJSON(env.USE_QEMU)
-    
+
     - name: Support long paths
-      if: runner.os == 'Windows' && ((!matrix.use_qemu) || fromJSON(env.USE_QEMU))
+      if: runner.os == 'Windows'
       run: git config --system core.longpaths true
 
+    - name: Set up msvc on Windows
+      if: runner.os == 'Windows'
+      uses: ilammy/msvc-dev-cmd@v1
+      with:
+        arch: ${{ matrix.arch }}
+
     - name: Export macOS SDKROOT
       if: runner.os == 'macOS'
       run: echo SDKROOT=$(xcrun --sdk macosx --show-sdk-path) >> $GITHUB_ENV
@@ -89,54 +76,28 @@ jobs:
     - name: Override LLVM version (${{ github.event.inputs.llvm_version }})
       if: github.event.inputs.llvm_version
       run: |
-        echo "set(CLANG_TIDY_VERSION ${{ github.event.inputs.llvm_version }})" > clang-tidy_version.cmake
-        echo "set(CLANG_TIDY_WHEEL_VERSION ${{ github.event.inputs.wheel_version }})" >> clang-tidy_version.cmake
-
-    - name: Set up QEMU
-      uses: docker/setup-qemu-action@v2.2.0
-      if: runner.os == 'Linux' && ((matrix.use_qemu) && fromJSON(env.USE_QEMU))
-
-    - uses: actions/setup-python@v5
-      with:
-        python-version: 3.8
-      # the pre-installed python 3.8 isn't native and cannot produce ARM64 wheels
-      # see also https://github.com/pypa/cibuildwheel/pull/1871
-      if: runner.os == 'macOS' && runner.arch == 'arm64'
+        echo "${{ github.event.inputs.llvm_version }}.${{ github.event.inputs.wheel_version }}" > clang-tidy_version.txt
+        cat clang-tidy_version.txt
 
     - name: Build wheels
       uses: pypa/cibuildwheel@v2.22.0
-      if: (!matrix.use_qemu) || fromJSON(env.USE_QEMU)
       env:
         CIBW_ARCHS: "${{ matrix.arch }}"
-        CIBW_BEFORE_TEST:  rm -rf {package}/clang_tidy
+        CIBW_BEFORE_TEST: rm -rf {package}/clang_tidy
         CIBW_TEST_SKIP: "*linux*"
         # always skip PyPY builds + what's defined in the matrix
         CIBW_SKIP: "pp* ${{matrix.skip}}"
-    # clang-tidy simply does not want to cooperate with the github linux image
-    - name: Test Linux Wheel
-      if: runner.os == 'Linux' && !(matrix.use_qemu) && matrix.arch == 'x86_64'
-      run: |
-        if [[ "${{matrix.skip}}" == "*manylinux*" ]] ; then
-          docker build --build-arg BASEOS=alpine3.16 --build-arg PLATFORM=musllinux -f .github/workflows/Dockerfile .
-        else
-          docker build --build-arg BASEOS=slim-bullseye --build-arg PLATFORM=manylinux -f .github/workflows/Dockerfile .        
-        fi
-    - name: Set artifact name
-      id: set_artifact_name
-      shell: bash -l {0}
-      run: |
-        VALUE="archive_wheels_${{ matrix.os }}_${{ matrix.arch }}_${{ matrix.skip }}"
-        VALUE="${VALUE//\*/}"
-        echo "value=${VALUE}" >> ${GITHUB_OUTPUT}
+        # restrict to a single Python version as wheel does not depend on Python:
+        CIBW_BUILD: "cp311-${{ matrix.platform }}*"
+
     - uses: actions/upload-artifact@v4
-      if: (!matrix.use_qemu) || fromJSON(env.USE_QEMU)
       with:
+        name: artifacts-wheels-${{ matrix.platform }}-${{ matrix.arch }}
         path: ./wheelhouse/*.whl
-        name: ${{ steps.set_artifact_name.outputs.value }}
 
   build-sdist:
     name: Build source distribution
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-latest
 
     steps:
       - uses: actions/checkout@v4
@@ -144,21 +105,20 @@ jobs:
       - name: Override LLVM version (${{ github.event.inputs.llvm_version }})
         if: github.event.inputs.llvm_version
         run: |
-          echo "set(CLANG_TIDY_VERSION ${{ github.event.inputs.llvm_version }})" > clang-tidy_version.cmake
-          echo "set(CLANG_TIDY_WHEEL_VERSION ${{ github.event.inputs.wheel_version }})" >> clang-tidy_version.cmake
- 
+          echo "${{ github.event.inputs.llvm_version }}.${{ github.event.inputs.wheel_version }}" > clang-tidy_version.txt
+          cat clang-tidy_version.txt
       - name: Build SDist
         run: pipx run build --sdist
 
       - uses: actions/upload-artifact@v4
         with:
           path: dist/*.tar.gz
-          name: archive_sdist
-  
+          name: artifacts-sdist
+
   test-sdist:
     name: Test build from source distribution
     needs: [build-sdist]
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-latest
 
     steps:
       - uses: actions/checkout@v4
@@ -166,16 +126,15 @@ jobs:
       - uses: actions/setup-python@v5
         name: Install Python
         with:
-          python-version: '3.9'
+          python-version: '3.13'
 
       - uses: actions/download-artifact@v4
         with:
-          name: archive_sdist
+          name: artifacts-sdist
           path: sdist
 
       - name: Install from SDist
         run: |
-          # make sure the test will not pick this up  
           rm -r clang_tidy
           pip install sdist/*.tar.gz
 
@@ -190,27 +149,29 @@ jobs:
   upload_pypi:
     name: Upload to PyPI
     needs: [build-wheels, build-sdist, test-sdist]
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-latest
+    permissions:
+      id-token: write
+      contents: write
     if: github.repository_owner == 'ssciwr'
 
     steps:
       - uses: actions/download-artifact@v4
         with:
-          pattern: archive*
-          path: dist
+          pattern: artifacts-*
           merge-multiple: true
+          path: dist
 
       - name: Upload to PyPI
-        uses: pypa/gh-action-pypi-publish@v1.8.11
-        if: github.event.inputs.deploy_to_testpypi == 'false'
-        with:
-          user: __token__
-          password: ${{ secrets.PYPI_API_TOKEN }}
+        uses: pypa/gh-action-pypi-publish@v1.12.3
+        if: (startsWith(github.event.ref, 'refs/tags/')) || (github.event.inputs.deploy_to_testpypi == 'false')
 
       - name: Upload to TestPyPI
-        uses: pypa/gh-action-pypi-publish@v1.8.11
+        uses: pypa/gh-action-pypi-publish@v1.12.3
         if: github.event.inputs.deploy_to_testpypi == 'true'
         with:
-          user: __token__
-          password: ${{ secrets.TESTPYPI_API_TOKEN }}
-          repository_url: https://test.pypi.org/legacy/
+          repository-url: https://test.pypi.org/legacy/
+
+      - name: GitHub release for tagged commits
+        uses: softprops/action-gh-release@v2
+        if: startsWith(github.ref, 'refs/tags/')
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 0f2ecc0..5d00828 100644
--- a/.gitignore
+++ b/.gitignore
@@ -185,3 +185,13 @@ _deps
 _skbuild/
 
 clang_tidy/data/
+
+# Standard temporal folder.
+tmp/
+
+# cibuild standard output of the wheels
+wheelhouse/
+
+# IDE configuration folders
+.vscode/
+.idea/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e684940..0ad16eb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,14 +1,13 @@
-project(clang-tidy-wheel)
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.16...3.31)
+project(${SKBUILD_PROJECT_NAME} VERSION ${SKBUILD_PROJECT_VERSION})
 
-# Include the "single source of truth" for the clang-tidy version
-include(clang-tidy_version.cmake)
-string(REPLACE "-" "" CLANG_TIDY_VERSION_SHORT "${CLANG_TIDY_VERSION}")
-string(REPLACE "." ";" CLANG_TIDY_VERSION_LIST ${CLANG_TIDY_VERSION})
-list(GET CLANG_TIDY_VERSION_LIST 0 CLANG_TIDY_VERSION_MAJOR)
+message(STATUS "clang-tidy-wheel version: ${SKBUILD_PROJECT_VERSION}")
+string(REGEX MATCH "^([0-9]+)\.([0-9]+)\.([0-9]+)" CLANG_TIDY_VERSION "${SKBUILD_PROJECT_VERSION}")
+set(CLANG_TIDY_VERSION_MAJOR ${CMAKE_MATCH_1}) # https://cmake.org/cmake/help/latest/variable/CMAKE_MATCH_n.html
+message(STATUS "clang-tidy version: ${CLANG_TIDY_VERSION}")
 
 # Define a build rule clang-tidy
-set(LLVM_DOWNLOAD_URL "https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_TIDY_VERSION}/llvm-project-${CLANG_TIDY_VERSION_SHORT}.src.tar.xz")
+set(LLVM_DOWNLOAD_URL "https://github.com/llvm/llvm-project/releases/download/llvmorg-${CLANG_TIDY_VERSION}/llvm-project-${CLANG_TIDY_VERSION}.src.tar.xz")
 include(ExternalProject)
 ExternalProject_add(build-clang-tidy
   URL "${LLVM_DOWNLOAD_URL}"
@@ -23,7 +22,12 @@ ExternalProject_add(build-clang-tidy
   CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DLLVM_ENABLE_ZSTD=OFF -DLLVM_ENABLE_PROJECTS=clang$<SEMICOLON>clang-tools-extra
   BUILD_COMMAND ${CMAKE_COMMAND} --build . --target clang-tidy
 )
-set(clang-tidy-executable ${CMAKE_BINARY_DIR}/llvm/bin/clang-tidy${CMAKE_EXECUTABLE_SUFFIX})
+
+set(config-subfolder "")
+if(CMAKE_GENERATOR MATCHES "Visual Studio")
+  set(config-subfolder "Release")
+endif()
+set(clang-tidy-executable ${CMAKE_BINARY_DIR}/llvm/${config-subfolder}/bin/clang-tidy${CMAKE_EXECUTABLE_SUFFIX})
 
 # Reduce the size of the executable by executing strip if it is present on the system
 find_program(STRIP_EXECUTABLE strip)
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 6cacc3a..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,6 +0,0 @@
-include clang-tidy_version.cmake
-include CMakeLists.txt
-include LICENSE.md
-include COPYING.md
-include README.md
-include pyproject.toml
diff --git a/clang-tidy_version.cmake b/clang-tidy_version.cmake
deleted file mode 100644
index ee43991..0000000
--- a/clang-tidy_version.cmake
+++ /dev/null
@@ -1,2 +0,0 @@
-set(CLANG_TIDY_VERSION 14.0.6)
-set(CLANG_TIDY_WHEEL_VERSION 0)
diff --git a/clang-tidy_version.txt b/clang-tidy_version.txt
new file mode 100644
index 0000000..094e9e5
--- /dev/null
+++ b/clang-tidy_version.txt
@@ -0,0 +1 @@
+19.1.6.0
diff --git a/pyproject.toml b/pyproject.toml
index 7e9c576..b456ac7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,15 +1,56 @@
 [build-system]
-requires = ["setuptools>=42", "wheel", "scikit-build", "cmake>=3.16", "ninja; platform_system!='Windows'"]
+requires = ["scikit-build-core"]
+build-backend = "scikit_build_core.build"
+
+[project]
+name = "clang-tidy"
+dynamic = ["version"]
+authors = [{name = "Dominic Kempf", email = "ssc@iwr.uni-heidelberg.de"}]
+license = { text = "Apache 2.0" }
+description = "Clang-tidy is an LLVM-based code analyser tool"
+readme = "README.md"
+classifiers = [
+    "Programming Language :: C",
+    "Programming Language :: C++",
+    "Operating System :: OS Independent",
+    "License :: OSI Approved :: Apache Software License",
+    "Intended Audience :: Developers",
+    "Topic :: Software Development :: Quality Assurance",
+]
+
+[tool.scikit-build.metadata.version]
+provider = "scikit_build_core.metadata.regex"
+regex = '^(?P<value>\d+\.\d+\.\d+(\.[1-9]\d*)?)'
+input = "clang-tidy_version.txt"
+
+[project.urls]
+Clang = "http://clang.llvm.org/"
+Documentation = "https://clang.llvm.org/extra/clang-tidy/index.html#clang-tidy"
+Download = "https://github.com/llvm/llvm-project/releases"
+Source = "https://github.com/ssciwr/clang-tidy-wheel"
+
+
+[project.scripts]
+"clang-tidy" = "clang_tidy:clang_tidy"
+
+[tool.scikit-build]
+wheel.packages = ["clang_tidy"]
+wheel.py-api = "py2.py3"
+cmake.version = ">=3.16.0"
+ninja.version = ">=1.10.0"
+cmake.verbose = true
+logging.level = "DEBUG"
 
 [tool.cibuildwheel]
 # Super-verbose output for debugging purpose
 build-verbosity = 3
-
-# We restrict ourselves to CPython 3.8 and then repair the wheels to be
-# independent of the Python version - I have not found a different solution
-# within cibuildwheel to achieve this.
-build = "cp38-*"
+# Set CMAKE_GENERATOR env var which is respected by scikit-build-core to use Ninja on all platforms
+environment = "CMAKE_GENERATOR=Ninja"
 
 # Testing commands for our wheels
-test-requires = ["pytest"]
+before-test = [
+    "git config --global user.name Name",
+    "git config --global user.email foo@bar.com"
+]
+test-requires = ["pytest", "pytest-git"]
 test-command = "pytest {package}/test"
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 4b68548..0000000
--- a/setup.py
+++ /dev/null
@@ -1,68 +0,0 @@
-
-from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
-from skbuild import setup
-
-import re
-
-class genericpy_bdist_wheel(_bdist_wheel):
-    def finalize_options(self):
-        _bdist_wheel.finalize_options(self)
-        self.root_is_pure = False
-
-    def get_tag(self):
-        python, abi, plat = _bdist_wheel.get_tag(self)
-        python, abi = "py2.py3", "none"
-        return python, abi, plat
-
-# Read the clang-tidy version from the "single source of truth"
-def get_version():
-    with open("clang-tidy_version.cmake", "r") as version_file:
-        parsed = {}
-        for line in version_file:
-            match = re.match("set\((.*) (.*)\)", line)
-            if len(match.groups()) != 2:
-                raise ValueError("Version File not readable")
-            parsed[match.groups()[0]] = match.groups()[1]
-        if parsed['CLANG_TIDY_WHEEL_VERSION'] == "0":
-            return f"{parsed['CLANG_TIDY_VERSION']}"
-        else:
-            return f"{parsed['CLANG_TIDY_VERSION']}.{parsed['CLANG_TIDY_WHEEL_VERSION']}"
-
-
-# Parse the given README file
-with open("README.md", "r") as readme_file:
-    readme = readme_file.read()
-
-cmdclass = {"bdist_wheel": genericpy_bdist_wheel}
-setup(
-    name="clang-tidy",
-    version=get_version(),
-    cmdclass=cmdclass,
-    author="Dominic Kempf",
-    author_email="ssc@iwr.uni-heidelberg.de",
-    packages=["clang_tidy"],
-    zip_safe=False,
-    entry_points={
-        "console_scripts": [
-            "clang-tidy=clang_tidy:clang_tidy",
-        ]
-    },
-    description="clang-tidy is a clang-based C++ “linter” tool.",
-    long_description=readme,
-    long_description_content_type="text/markdown",
-    url="http://clang.llvm.org/",
-    project_urls={
-        "Documentation": "https://clang.llvm.org/extra/clang-tidy/",
-        "Source": "https://github.com/ssciwr/clang-tidy-wheel"
-    },
-    download_url="https://github.com/llvm/llvm-project/releases",
-    classifiers=[
-        "Programming Language :: C",
-        "Programming Language :: C++",
-        "Operating System :: OS Independent",
-        "License :: OSI Approved :: Apache Software License",
-        "Intended Audience :: Developers",
-        "Topic :: Software Development :: Quality Assurance",
-    ],
-    license="Apache 2.0"
-)