add linter
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..9913057
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,2 @@
+BasedOnStyle: LLVM
+SortIncludes: false
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..0cbe7b9
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,10 @@
+
+Our CI tests check formatting automating. If such a test fails, please consider running the bash script:
+
+```bash
+bash script/run-clangcldocker.sh
+```
+
+Make sure that you have [docker installed and running](https://docs.docker.com/engine/install/) on your system. Most Linux distributions support docker though some (like RedHat) have the equivalent (Podman). Users of Apple systems may want to [consider OrbStack](https://orbstack.dev). You do not need to familiar with docker, you just need to make sure that you are have it running.
+
+If you are unable to format the code, we may format it for you.
diff --git a/.github/workflows/lint_and_format_check.yml b/.github/workflows/lint_and_format_check.yml
new file mode 100644
index 0000000..5f39e65
--- /dev/null
+++ b/.github/workflows/lint_and_format_check.yml
@@ -0,0 +1,33 @@
+name: Lint and format
+
+on:
+  pull_request:
+    types: [opened, synchronize, reopened, ready_for_review]
+    paths-ignore:
+      - '**.md'
+      - 'docs/**'
+  push:
+    branches:
+      - main
+    paths-ignore:
+      - '**.md'
+      - 'docs/**'
+
+permissions:
+  contents: read
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  lint-and-format:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
+
+      - name: Run clang-format
+        uses: jidicula/clang-format-action@c74383674bf5f7c69f60ce562019c1c94bc1421a # v4.13.0
+        with:
+          clang-format-version: '17'
+
diff --git a/script/run-clangcldocker.sh b/script/run-clangcldocker.sh
new file mode 100644
index 0000000..62a1df5
--- /dev/null
+++ b/script/run-clangcldocker.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+set -e
+COMMAND=$*
+SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
+MAINSOURCE=$SCRIPTPATH/..
+ALL_FILES=$(cd $MAINSOURCE && git ls-tree --full-tree --name-only -r HEAD | grep -e ".*\.\(c\|h\|cc\|cpp\|hh\)\$" | grep -vFf clang-format-ignore.txt)
+
+if clang-format-17 --version  2>/dev/null | grep -qF 'version 17.'; then
+  cd $MAINSOURCE; clang-format-17 --style=file --verbose -i "$@" $ALL_FILES
+  exit 0
+elif clang-format --version  2>/dev/null | grep -qF 'version 17.'; then
+  cd $MAINSOURCE; clang-format --style=file --verbose -i "$@" $ALL_FILES
+  exit 0
+fi
+echo "Trying to use docker"
+command -v docker >/dev/null 2>&1 || { echo >&2 "Please install docker. E.g., go to https://www.docker.com/products/docker-desktop Type 'docker' to diagnose the problem."; exit 1; }
+docker info >/dev/null 2>&1 || { echo >&2 "Docker server is not running? type 'docker info'."; exit 1; }
+
+if [ -t 0 ]; then DOCKER_ARGS=-it; fi
+docker pull kszonek/clang-format-17
+
+docker run --rm $DOCKER_ARGS -v "$MAINSOURCE":"$MAINSOURCE":Z  -w "$MAINSOURCE" -u "$(id -u $USER):$(id -g $USER)" kszonek/clang-format-17 --style=file --verbose -i "$@" $ALL_FILES