diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml
new file mode 100644
index 0000000000000000000000000000000000000000..287796fb422cd32a4255dbe54d8c1ed34f997749
--- /dev/null
+++ b/.github/workflows/documentation.yml
@@ -0,0 +1,70 @@
+name: Documentation
+
+on:
+  push:
+    branches: [ master, release-* ]
+    paths:
+      - '**.md'
+  pull_request:
+    branches: [ master, release-* ]
+    paths:
+      - '**.md'
+
+jobs:
+  quality:
+    name: Quality checks
+    runs-on: [ubuntu-latest]
+
+    steps:
+      - name: Setup PHP, with composer and extensions
+        uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
+        with:
+          php-version: '8.0'
+          tools: composer:v2
+          extensions: intl, mbstring, xml
+
+      - name: Setup problem matchers for PHP
+        run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
+
+      - uses: actions/checkout@v3
+
+      - name: Get composer cache directory
+        id: composer-cache
+        run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+      - name: Cache composer dependencies
+        uses: actions/cache@v3
+        with:
+            path: ${{ steps.composer-cache.outputs.dir }}
+            key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+            restore-keys: ${{ runner.os }}-composer-
+
+      - name: Install Composer dependencies
+        run: composer install --no-progress --prefer-dist --optimize-autoloader
+
+      - name: Lint markdown files
+        uses: nosborn/github-action-markdown-cli@v3.1.0
+        with:
+          files: .
+          ignore_path: .markdownlintignore
+
+  build:
+    name: Build documentation
+    needs: quality
+    runs-on: [ubuntu-latest]
+
+    steps:
+      - name: Run docs build if any of markdown-files have changed
+        if: steps.changed-files-specific.outputs.any_changed == 'true' && github.event_name != 'pull_request'
+        uses: actions/github-script@v6
+        with:
+          # Token has to be generated on a user account that controls the docs-repository.
+          # The _only_ scope to select is "Access public repositories", nothing more.
+          github-token: ${{ secrets.PAT_TOKEN }}
+          script: |
+            await github.rest.actions.createWorkflowDispatch({
+              owner: 'simplesamlphp',
+              repo: 'docs',
+              workflow_id: 'mk_docs.yml',
+              ref: 'main'
+            })
diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
index ba59d41e96c997ed4249dbee1be0af9d6fa8d82b..a85f4aa085d97cb4655f976d4ba1e798c167d692 100644
--- a/.github/workflows/php.yml
+++ b/.github/workflows/php.yml
@@ -37,7 +37,7 @@ jobs:
           git config --global core.autocrlf false
           git config --global core.eol lf
 
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
 
       - name: Get composer cache directory
         id: composer-cache
@@ -91,7 +91,7 @@ jobs:
       - name: Setup problem matchers for PHP
         run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
 
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
 
       - name: Get composer cache directory
         id: composer-cache
@@ -132,7 +132,7 @@ jobs:
       - name: Setup problem matchers for PHP
         run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
 
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
 
       - name: Get composer cache directory
         id: composer-cache
@@ -170,7 +170,7 @@ jobs:
       - name: Setup problem matchers for PHP
         run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
 
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
 
       - name: Get composer cache directory
         id: composer-cache
diff --git a/.markdownlintignore b/.markdownlintignore
new file mode 100644
index 0000000000000000000000000000000000000000..140fada73f4e74552a2c5e757c9a4b81b4cd36b0
--- /dev/null
+++ b/.markdownlintignore
@@ -0,0 +1 @@
+vendor/*