diff --git a/.github/actions/docker-deploy/action.yaml b/.github/actions/docker-deploy/action.yaml
new file mode 100644
index 0000000..d9cbc5b
--- /dev/null
+++ b/.github/actions/docker-deploy/action.yaml
@@ -0,0 +1,64 @@
+
+name: docker-deploy-image
+
+inputs:
+  registry:
+    description: 'The registry to push the image to'
+    required: false
+    default: ''
+  registry_username:
+    description: 'The username to use to push the image'
+    required: false
+    default: ''
+  registry_password:
+    description: 'The password to use to push the image'
+    required: false
+    default: ''
+  image_name:
+    description: 'The name of the image to push'
+    required: false
+    default: ''
+  platforms:
+    description: 'The platforms to build the image for'
+    required: false
+    default: 'linux/amd64,linux/arm64'
+  push:
+    description: 'Whether to push the image'
+    required: false
+    default: false
+
+runs:
+  using: composite
+  steps:
+    - name: Set up QEMU
+      uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
+
+    - name: Set up Docker Buildx
+      uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
+
+    - name: Log in to the Container registry
+      if: ${{ inputs.push == true || inputs.push == 'true' }}
+      uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
+      with:
+        registry: ${{ inputs.registry }}
+        username: ${{ inputs.registry_username }}
+        password: ${{ inputs.registry_password }}
+
+    - name: Extract metadata (tags, labels) for Docker
+      id: meta
+      uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1
+      with:
+        images: ${{ inputs.registry }}/${{ inputs.image_name }}
+        tags: |
+          type=semver,pattern={{version}}
+          type=pep440,pattern={{version}}
+          type=ref,event=branch
+
+    - name: Build and push Docker image
+      uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0
+      with:
+        context: .
+        push: ${{ inputs.push }}
+        tags: ${{ steps.meta.outputs.tags }}
+        labels: ${{ steps.meta.outputs.labels }}
+        platforms: ${{ inputs.platforms }}
diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml
new file mode 100644
index 0000000..ed98136
--- /dev/null
+++ b/.github/workflows/docker-build.yaml
@@ -0,0 +1,25 @@
+name: docker-build-image
+
+on:
+  pull_request:
+
+concurrency:
+  group: "docker-build-${{ github.head_ref || github.ref }}"
+  cancel-in-progress: true
+
+jobs:
+  build-image:
+    runs-on: ubuntu-latest
+
+    permissions:
+      contents: read
+
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+      - name: Build docker images
+        uses: ./.github/actions/docker-deploy
+        with:
+          image_name: ${{ github.repository }}
+          push: false
diff --git a/.github/workflows/docker-deploy-branch.yaml b/.github/workflows/docker-deploy-branch.yaml
new file mode 100644
index 0000000..0475531
--- /dev/null
+++ b/.github/workflows/docker-deploy-branch.yaml
@@ -0,0 +1,27 @@
+name: docker-deploy-branch
+
+on:
+  push:
+    branches:
+      - master
+
+jobs:
+  build-and-push-image:
+    runs-on: ubuntu-latest
+
+    permissions:
+      contents: read
+      packages: write
+
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+      - name: Deploy docker images
+        uses: ./.github/actions/docker-deploy
+        with:
+          registry: ghcr.io
+          registry_username: ${{ github.actor }}
+          registry_password: ${{ secrets.GITHUB_TOKEN }}
+          image_name: ${{ github.repository }}
+          push: true
diff --git a/.github/workflows/docker-deploy-tag.yaml b/.github/workflows/docker-deploy-tag.yaml
new file mode 100644
index 0000000..1eca264
--- /dev/null
+++ b/.github/workflows/docker-deploy-tag.yaml
@@ -0,0 +1,27 @@
+name: docker-deploy-tag
+
+on:
+  push:
+    tags:
+      - 'v*.*.*'
+
+jobs:
+  build-and-push-image:
+    runs-on: ubuntu-latest
+
+    permissions:
+      contents: read
+      packages: write
+
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+      - name: Deploy docker images
+        uses: ./.github/actions/docker-deploy
+        with:
+          registry: ghcr.io
+          registry_username: ${{ github.actor }}
+          registry_password: ${{ secrets.GITHUB_TOKEN }}
+          image_name: ${{ github.repository }}
+          push: true
diff --git a/.github/workflows/pr-title-checker.yaml b/.github/workflows/pr-title-checker.yaml
new file mode 100644
index 0000000..e537e6c
--- /dev/null
+++ b/.github/workflows/pr-title-checker.yaml
@@ -0,0 +1,28 @@
+name: pr-title-checker
+
+on:
+  pull_request_target:
+    types:
+      - opened
+      - edited
+      - synchronize
+      - reopened
+  merge_group:
+
+concurrency:
+  group: "title-checker-${{ github.head_ref || github.ref }}"
+  cancel-in-progress: true
+
+permissions:
+  pull-requests: read
+
+jobs:
+  pr_title_checker:
+    name: validate
+    # Skip merge-queue PRs
+    if: contains(github.ref_name, 'gh-readonly-queue/main/') != true
+    runs-on: ubuntu-latest
+    steps:
+      - uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release-please.yaml b/.github/workflows/release-please.yaml
new file mode 100644
index 0000000..075ea24
--- /dev/null
+++ b/.github/workflows/release-please.yaml
@@ -0,0 +1,20 @@
+name: release-please
+
+on:
+  push:
+    branches:
+      - master
+
+permissions:
+  contents: write
+  pull-requests: write
+
+jobs:
+  release-please:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: googleapis/release-please-action@d1a8f221d7723166f48a584aebba00ef3f6febec
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }} # Should be changed to a PAT, so that we can trigger a workflow on tag push from the CI
+          config-file: release-please-config.json
+          manifest-file: .release-please-manifest.json
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
new file mode 100644
index 0000000..309e65c
--- /dev/null
+++ b/.release-please-manifest.json
@@ -0,0 +1,3 @@
+{
+  ".": ""
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..e69de29
diff --git a/release-please-config.json b/release-please-config.json
new file mode 100644
index 0000000..b558a59
--- /dev/null
+++ b/release-please-config.json
@@ -0,0 +1,12 @@
+{
+  "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
+  "release-type": "simple",
+  "include-v-in-tag": false,
+  "include-component-in-tag": false,
+  "bump-minor-pre-major": true,
+  "packages": {
+    ".": {
+      "package-name": "discv4-crawl"
+    }
+  }
+}
diff --git a/version.txt b/version.txt
new file mode 100644
index 0000000..e69de29