diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 0000000000000000000000000000000000000000..5c744faa66dcb7bd69b281fcac47474f4faaaf23
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,34 @@
+---
+Checks:          'clang-diagnostic-*,clang-analyzer-*,bugprone-*'
+WarningsAsErrors: ''
+HeaderFilterRegex: ''
+AnalyzeTemporaryDtors: false
+FormatStyle:     none
+User:            swym
+CheckOptions:    
+  - key:             cert-dcl16-c.NewSuffixes
+    value:           'L;LL;LU;LLU'
+  - key:             cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
+    value:           '1'
+  - key:             google-readability-braces-around-statements.ShortStatementLines
+    value:           '1'
+  - key:             google-readability-function-size.StatementThreshold
+    value:           '800'
+  - key:             google-readability-namespace-comments.ShortNamespaceLines
+    value:           '10'
+  - key:             google-readability-namespace-comments.SpacesBeforeComments
+    value:           '2'
+  - key:             modernize-loop-convert.MaxCopySize
+    value:           '16'
+  - key:             modernize-loop-convert.MinConfidence
+    value:           reasonable
+  - key:             modernize-loop-convert.NamingStyle
+    value:           CamelCase
+  - key:             modernize-pass-by-value.IncludeStyle
+    value:           llvm
+  - key:             modernize-replace-auto-ptr.IncludeStyle
+    value:           llvm
+  - key:             modernize-use-nullptr.NullMacros
+    value:           'NULL'
+...
+
diff --git a/.gitignore b/.gitignore
index 5fa9e7b85f0f2845bc58e69bcb37946059df8c64..7ca9401ea28a47e1b80f555fb902d358728fc8bc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ __pycache__/
 *.pyc
 .*.swp
 *~
+compile_commands.json
diff --git a/meson.build b/meson.build
index 96a11fe4fbbb6d294c530a42102311989dbe542a..3dd0578c22938b2bafa857aca91a2625f3b2ac0e 100644
--- a/meson.build
+++ b/meson.build
@@ -46,6 +46,22 @@ version_hdr = custom_target(
   command: [files('tools/version-header.sh'), '@OUTPUT@'],
 )
 
+jq = find_program('jq', required: false)
+if jq.found()
+  compile_commands = custom_target(
+    'compile_commands_tidy.json',
+    build_by_default: true,
+    output: 'compile_commands_tidy.json',
+    command: [
+      files('tools/convert-ccjson.sh'),
+      meson.current_source_dir(),
+      meson.current_build_dir(),
+      '@OUTPUT@',
+    ],
+  )
+endif
+
+
 subdir('lib/')
 subdir('bootloader/')
 
diff --git a/tools/compile_commands.jq b/tools/compile_commands.jq
new file mode 100644
index 0000000000000000000000000000000000000000..ac0e3138701a67aa75ff8f6b3ecadb801b73b0ec
--- /dev/null
+++ b/tools/compile_commands.jq
@@ -0,0 +1,11 @@
+[.[]|({
+    directory:.directory,
+    command:(. as {file:$file, directory:$directory}
+        |.command
+        |sub("-fno-isolate-erroneous-paths-dereference";"-m32")
+        |sub("(?<a>\\s)\\.\\./"; (.a) + "\($directory)/../")
+        |sub("/build/\\.\\./"; "/")
+        )
+    ,
+    file:((.directory|sub("build$";""))+(.file|sub("^../";"")))
+})]
diff --git a/tools/convert-ccjson.sh b/tools/convert-ccjson.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8e444e270aced0b920efb41c874fd927eb39af3b
--- /dev/null
+++ b/tools/convert-ccjson.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+set -e
+
+if [[ "$#" == 0 ]]; then
+    echo "usage: $0 <sourcedir> <compile_commands_file>"
+    exit 1
+fi
+
+script_dir="$(dirname "$0")"
+source_dir="$1"
+build_dir="$2"
+output="$3"
+
+jq -f "$script_dir/compile_commands.jq" "$build_dir/compile_commands.json" >"$source_dir/compile_commands.json"
+
+if [[ "$output" != "" ]]; then
+    touch "$output"
+fi