diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7e7dd356c18548bde1ef011060aea8f87765c708..4b893897a3752949819d3c0ec2d0fb018c9db793 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -8,6 +8,22 @@ build:
         - ninja -C build/
         - arm-none-eabi-size build/bootloader/bootloader.elf build/epicardium/epicardium.elf build/pycardium/pycardium.elf
 
+lint:
+    stage: test
+    image: "registry.k0.hswaw.net/q3k/card10-lint-env:20190728-233522Z-ded74f0-dirty"
+    script:
+        # Annoyatron is maintained by q3k. Its job is to serve MR comments that are friendlier than just a failing pipeline.
+        #  source code: https://git.card10.badge.events.ccc.de/q3k/annoyatron/
+        #  prod deployment: https://gerrit.hackerspace.pl/plugins/gitiles/hscloud/+/refs/heads/master/personal/q3k/annoyatron/
+        # If this starts failing for any reason, just remove this curl ping.
+        - curl --fail https://annoyatron-prod.q3k.org/ping/mr?mr=${CI_MERGE_REQUEST_IID}
+        - git remote rm card10 || true # old gitlab runners might have this remote.
+        - git fetch https://git.card10.badge.events.ccc.de/card10/firmware.git master:card10/master
+        - git diff --name-only $(git merge-base --fork-point card10/master)...HEAD | xargs tools/code-style.sh
+        - git diff --exit-code
+    only:
+        - merge_requests
+
 pages:
     stage: deploy
     # maintaned by q3k, build using docker/deploy-env
diff --git a/docker/lint-env/Dockerfile b/docker/lint-env/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..0085b57c62b6c25387d151b310a32fa165dcc85c
--- /dev/null
+++ b/docker/lint-env/Dockerfile
@@ -0,0 +1,15 @@
+FROM ubuntu:bionic
+
+RUN set -e -x ;\
+    export DEBIAN_FRONTEND=noninteractive ;\
+    apt-get update -y ;\
+    apt-get install -y \
+        curl \
+        ca-certificates \
+        clang-format \
+        git \
+        python3 \
+        python3-pip ;\
+    python3 -m pip install black ;\
+    rm -rf /var/lib/apt/lists
+
diff --git a/docker/lint-env/push.sh b/docker/lint-env/push.sh
new file mode 100755
index 0000000000000000000000000000000000000000..08cc60924ae33b9d53c32fd435eb2d8dbeb85787
--- /dev/null
+++ b/docker/lint-env/push.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+# Build and push the deploy env Docker container to the Gitlab container registry.
+
+set -e
+
+function rev() {
+    ( cd $1; git describe --always --match "v[0-9].*" --dirty )
+}
+
+IMAGE=registry.k0.hswaw.net/q3k/card10-lint-env
+TAG=$(TZ=UTC date +%Y%m%d-%H%M%SZ)-$(rev .)
+
+docker build -t $IMAGE:$TAG .
+docker push $IMAGE:$TAG
+
+echo "Pushed $IMAGE:$TAG"
diff --git a/tools/code-style.sh b/tools/code-style.sh
index b6943dbdcf37ac777cd53d4adc6327674353f6a0..295b77b9204b7427d8e663999942a0f1ec1980a2 100755
--- a/tools/code-style.sh
+++ b/tools/code-style.sh
@@ -56,6 +56,5 @@ for source_file in "$@"; do
         black -q "$source_file"
     else
         echo " - Ignoring $source_file" >&2
-        continue
-    fi
+	fi
 done