diff --git a/.ci/apt-get-and-cache.sh b/.ci/apt-get-and-cache.sh
new file mode 100755
index 0000000000000000000000000000000000000000..be41da9d1528dac9aeeadca1dd13458e58c2cf84
--- /dev/null
+++ b/.ci/apt-get-and-cache.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# "apt update ; apt install", with caching of the downloaded packages
+# and current state, to minimise load on debian mirrors without having
+# to build a new docker image
+
+CACHE=.ci/debian-cache.tar.gz
+
+if [ -z "$1" ]; then
+    printf 'Usage: %s <package>...\n' "$0"
+    exit 1
+fi
+
+if ls -sh $CACHE; then
+    sudo tar xvaf $CACHE -C /var
+else
+    printf 'No debian cache to extract\n'
+fi
+
+# Remove the configuration that disable apt cache
+sudo rm /etc/apt/apt.conf.d/docker-clean
+
+sudo apt update -y -q
+# first only download the packages, so that they end up in the cache
+sudo DEBIAN_FRONTEND=noninteractive apt install -yqd "$@"
+sudo tar caf $CACHE -C /var lib/apt cache/apt
+ls -sh $CACHE
+
+# now really install the packages
+sudo DEBIAN_FRONTEND=noninteractive apt install -yq --no-download "$@"
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b7669ba432c4cb3d92665a4412d61b607991803f
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,20 @@
+image: "coqorg/coq:latest"
+
+build:
+  stage: build
+  script:
+    - .ci/apt-get-and-cache.sh ghc cabal-install libghc-language-c-dev libghc-wl-pprint-text-dev libghc-optparse-applicative-dev libghc-data-default-dev libghc-aeson-dev
+    - cabal build
+    - cp dist/build/digger/digger digger
+  cache:
+    paths:
+      - .ci/*-cache.tar.gz
+    when: 'always'
+  artifacts:
+    paths:
+      - digger
+
+test:
+  stage: test
+  script:
+    - make -C example