diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 579d6519890a03b19e83b372eab831efc4eb3b61..8a53abc7e67b899edf0fff5c788b9ba396a0e414 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -71,12 +71,21 @@ test:
     - octave -v
     - make test
 
-linting:
+linting_octave:
   tags: [ docker ]
   stage: test
   script:
     - mh_lint --octave ./
 
+linting_cpp:
+  tags: [ docker ]
+  stage: test
+  script:
+    - cd src
+    - ./configure
+    - cd ../build
+    - cmake -D LINTING=On ..
+    - cmake --build .
 
 # Build the sphinx documentation and make it ready for deployment by Gitlab Pages
 # Special job for serving a static website. See https://docs.gitlab.com/ee/ci/yaml/README.html#pages
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 630b51837485411fbc3e345d7d626de8be361040..66164782d2f551c03012038471f15e008e40e506 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,20 +42,92 @@ string(REGEX REPLACE ";grpc\\+?\\+?_unsecure" "" CONAN_LIBS
 string(REGEX REPLACE ";grpc\\+?\\+?_unsecure" "" CONAN_PKG_LIBS
     "${CONAN_PKG_LIBS}")
 
+#######################################################
+### code formatting with clang-format
+#######################################################
+option(AUTOFORMATTING "call clang-format at configure time" ON)
+if(AUTOFORMATTING)
+    file(GLOB format_sources src/*.cpp)
+    execute_process(COMMAND clang-format -i --verbose ${format_sources}
+        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
+endif()
+
+
+#######################################################
+### Compile *.mex files
+#######################################################
 add_subdirectory(src)
 set(PKG_INST_DIR "${PROJECT_SOURCE_DIR}/inst")
 
 file(MAKE_DIRECTORY ${PKG_INST_DIR})
-string(REGEX REPLACE ";" ";-I" MKOCTFILE_INCLUDES "-I${CONAN_INCLUDE_DIRS}")
-string(REGEX REPLACE ";" ";-L" MKOCTFILE_LIB_DIRS "-L${CONAN_LIB_DIRS}")
-string(REGEX REPLACE ";" ";-l" MKOCTFILE_LIBS "-l${CONAN_LIBS}")
-string(REGEX REPLACE ";" ":" MKOCTFILE_RPATH "${CONAN_LIB_DIRS}")
-set(MKOCTFILE_OPTIONS "-o" "${PKG_INST_DIR}/caosdb.mex" "-Wl,-rpath,${MKOCTFILE_RPATH}" "--mex" "-std=gnu++17"
-    "-L/usr/local/lib" ${MKOCTFILE_INCLUDES} ${MKOCTFILE_LIB_DIRS} ${MKOCTFILE_LIBS})
+string(REGEX REPLACE ";" ";-I" _MKOCTFILE_INCLUDES "-I${CONAN_INCLUDE_DIRS}")
+string(REGEX REPLACE ";" ";-L" _MKOCTFILE_LIB_DIRS "-L${CONAN_LIB_DIRS}")
+string(REGEX REPLACE ";" ";-l" _MKOCTFILE_LIBS "-l${CONAN_LIBS}")
+string(REGEX REPLACE ";" ":" _MKOCTFILE_RPATH "${CONAN_LIB_DIRS}")
+set(_MKOCTFILE_OPTIONS "-o" "${PKG_INST_DIR}/caosdb.mex" "-Wl,-rpath,${_MKOCTFILE_RPATH}" "--mex" "-std=gnu++17"
+    "-L/usr/local/lib" ${_MKOCTFILE_INCLUDES} ${_MKOCTFILE_LIB_DIRS} ${_MKOCTFILE_LIBS})
+
 add_custom_command(OUTPUT ${PKG_INST_DIR}/caosdb.mex
     COMMAND mkoctfile
-    ARGS ${MKOCTFILE_OPTIONS} ${OCTAVE_CAOSDB_SRC}
+    ARGS ${_MKOCTFILE_OPTIONS} ${OCTAVE_CAOSDB_SRC}
     DEPENDS ${OCTAVE_CAOSDB_SRC}
     )
 add_custom_target(caosdb.mex ALL
     SOURCES ${PKG_INST_DIR}/caosdb.mex)
+
+
+#######################################################
+### Linting with clang-tidy and include-what-you-use
+#######################################################
+option(LINTING "clang-tidy and iwyu" OFF)
+if(LINTING)
+    execute_process(COMMAND mkoctfile -p OCTINCLUDEDIR
+        OUTPUT_VARIABLE _OCTINCLUDEDIR
+        )
+    string(REGEX REPLACE "\n" "" _OCTINCLUDEDIR "${_OCTINCLUDEDIR}")
+
+    find_program(clang_tidy NAMES clang-tidy clang-tidy-11)
+    if(NOT clang_tidy)
+        message(WARNING "clang-tidy: Not found")
+    else()
+        message(STATUS "clang-tidy: ${clang_tidy}")
+        set(_CMAKE_CXX_CLANG_TIDY
+            "--warnings-as-errors=*"
+            "--fix")
+        set(_CMAKE_CXX_CLANG_TIDY_CHECKS
+          "--checks=*,-fuchsia-*,-llvmlibc-*,-llvm-else-after-return,-readability-else-after-return,-cppcoreguidelines-pro-type-vararg,-hicpp-vararg,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cert-err58-cpp")
+
+        add_custom_command(
+            TARGET caosdb.mex
+            COMMAND ${clang_tidy}
+            ARGS ${_CMAKE_CXX_CLANG_TIDY} ${_CMAKE_CXX_CLANG_TIDY_CHECKS}
+            ${OCTAVE_CAOSDB_SRC} "--" ${_MKOCTFILE_INCLUDES} "-I/usr/include"
+            "-I${_OCTINCLUDEDIR}" "-std=c++17"
+            DEPENDS ${OCTAVE_CAOSDB_SRC})
+    endif()
+
+    find_program(iwyu
+        NAMES include-what-you-use iwyu
+        PATHS ${CMAKE_SOURCE_DIR}/tools/include-what-you-use/${iwyu_os}/bin)
+    if(NOT iwyu)
+        message(WARNING "include-what-you-use: Not found")
+    else()
+        message(STATUS "include-what-you-use: ${iwyu}")
+        set(_CMAKE_CXX_INCLUDE_WHAT_YOU_USE
+            "-Xiwyu" "--no_fwd_decls"
+            "-Xiwyu" "--cxx17ns")
+
+        add_custom_command(
+            TARGET caosdb.mex
+            COMMAND ${iwyu}
+            ARGS ${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE} "-I${_OCTINCLUDEDIR}"
+            "-std=c++17" "-I/usr/include" ${_MKOCTFILE_INCLUDES}
+            ${OCTAVE_CAOSDB_SRC}
+            DEPENDS ${OCTAVE_CAOSDB_SRC})
+    endif()
+
+else()
+    message(STATUS "LINTING is OFF")
+endif()
+
+
diff --git a/src/caosdb.cpp b/src/caosdb.cpp
index 5b9845caf6daf6c5d9439311240de199bb42cd60..added8465e231fc361d743364bab7a0aed6b0bf0 100644
--- a/src/caosdb.cpp
+++ b/src/caosdb.cpp
@@ -1,9 +1,13 @@
-#include <string>
-#include "mex.h"
-#include "caosdb/connection.h"  // for Connection, ConnectionManager
-#include "caosdb/constants.h"   // for LIBCAOSDB_VERSION_MINOR, LIBCAOSDB_V...
-
-const char* print_version();
+#include <mex.h>               // for mxArray, mexFunction
+#include <string.h>            // for strcmp
+#include <memory>              // for unique_ptr, __shared_ptr_access, shar...
+#include <string>              // for allocator, char_traits, operator+
+#include "caosdb/connection.h" // for Connection, ConnectionManager
+#include "caosdb/constants.h"  // for LIBCAOSDB_VERSION_MAJOR, LIBCAOSDB_VE...
+#include "caosdb/info.h"       // for VersionInfo
+#include "mexproto.h"          // for mexPrintf, mxCreateString, mxGetChars
+
+auto print_version() -> const char *;
 void print_usage();
 void test_connection();
 
@@ -12,39 +16,39 @@ void print_usage() {
   mexPrintf("\nUsage: caosdb [OPTIONS]\n\n");
   mexPrintf("Options:\n");
   mexPrintf("    --help              Print this help and return.\n");
-  mexPrintf("    --version           Print the version of OcataveCaosDB and libcaosdb and return.\n");
-  mexPrintf("    --test-connection   Test the default connection and return.\n");
+  mexPrintf("    --version           Print the version of OcataveCaosDB and "
+            "libcaosdb and return.\n");
+  mexPrintf(
+    "    --test-connection   Test the default connection and return.\n");
 };
 
-const std::string FULL_VERSION = std::string("v0.1 (libcaosdb v"
-    + std::to_string(caosdb::LIBCAOSDB_VERSION_MAJOR) +
-    "." + std::to_string(caosdb::LIBCAOSDB_VERSION_MINOR) +
-    "." + std::to_string(caosdb::LIBCAOSDB_VERSION_PATCH) +
-    ")").c_str();
+const std::string FULL_VERSION = std::string(
+  "v0.1 (libcaosdb v" + std::to_string(caosdb::LIBCAOSDB_VERSION_MAJOR) + "." +
+  std::to_string(caosdb::LIBCAOSDB_VERSION_MINOR) + "." +
+  std::to_string(caosdb::LIBCAOSDB_VERSION_PATCH) + ")");
 
-const char* print_version() {
+auto print_version() -> const char * {
   mexPrintf("Octave caosdb client %s\n\n", FULL_VERSION.c_str());
   mexPrintf("We don't miss the H of caos.\n");
   return FULL_VERSION.c_str();
 };
 
 void test_connection() {
-  const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection();
+  const auto &connection =
+    caosdb::connection::ConnectionManager::GetDefaultConnection();
   const auto &version_info = connection->GetVersionInfo();
-  mexPrintf("Server Version: v%d.%d.%d-%s-%s\n",
-      version_info->GetMajor(),
-      version_info->GetMinor(),
-      version_info->GetPatch(),
-      version_info->GetPreRelease().c_str(),
-      version_info->GetBuild().c_str());
+  mexPrintf("Server Version: v%d.%d.%d-%s-%s\n", version_info->GetMajor(),
+            version_info->GetMinor(), version_info->GetPatch(),
+            version_info->GetPreRelease().c_str(),
+            version_info->GetBuild().c_str());
 }
 
-void mexFunction (int nlhs, mxArray *plhs[],
-                  int nrhs, const mxArray *prhs[]) {
+void mexFunction(int /*nlhs*/, mxArray *plhs[], int nrhs,
+                 const mxArray *prhs[]) {
 
   if (nrhs == 1) {
     auto const *first_arg = mxGetChars(prhs[0]);
-    if(strcmp(first_arg,"--version") == 0) {
+    if (strcmp(first_arg, "--version") == 0) {
       const auto *version = print_version();
       plhs[0] = mxCreateString(version);
       return;
@@ -54,5 +58,4 @@ void mexFunction (int nlhs, mxArray *plhs[],
     }
   }
   print_usage();
-
 }