diff --git a/.devcontainer/.bashrc b/.devcontainer/.bashrc
index 9fdb8f69..967fa144 100644
--- a/.devcontainer/.bashrc
+++ b/.devcontainer/.bashrc
@@ -6,3 +6,8 @@ fi
 if [ -f "$WORKSPACE_DIR/zephyr/zephyr-env.sh" ]; then
   source "$WORKSPACE_DIR/zephyr/zephyr-env.sh"
 fi
+
+if [ -d "$WORKSPACE_DIR/tools/bsim" ]; then
+  export BSIM_OUT_PATH="$WORKSPACE_DIR/tools/bsim/"
+  export BSIM_COMPONENTS_PATH="$WORKSPACE_DIR/tools/bsim/components/"
+fi
\ No newline at end of file
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 04a42c4d..efa8c229 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -13,9 +13,13 @@
     "type=volume,source=zmk-zephyr-modules,target=${containerWorkspaceFolder}/modules",
     "type=volume,source=zmk-zephyr-tools,target=${containerWorkspaceFolder}/tools"
   ],
-  "extensions": ["ms-vscode.cpptools"],
-  "settings": {
-    "terminal.integrated.shell.linux": "/bin/bash"
+  "customizations": {
+    "vscode": {
+      "extensions": ["ms-vscode.cpptools"],
+      "settings": {
+        "terminal.integrated.shell.linux": "/bin/bash"
+      }
+    }
   },
   "forwardPorts": [3000]
 }
diff --git a/.github/workflows/ble-test.yml b/.github/workflows/ble-test.yml
new file mode 100644
index 00000000..3bc8a718
--- /dev/null
+++ b/.github/workflows/ble-test.yml
@@ -0,0 +1,78 @@
+name: BLE Tests
+
+on:
+  push:
+    paths:
+      - ".github/workflows/ble-test.yml"
+      - "app/tests/ble/**"
+      - "app/src/**"
+      - "app/run-ble-test.sh"
+  pull_request:
+    paths:
+      - ".github/workflows/ble-test.yml"
+      - "app/tests/ble/**"
+      - "app/src/**"
+      - "app/run-ble-test.sh"
+
+jobs:
+  collect-tests:
+    outputs:
+      test-dirs: ${{ steps.test-dirs.outputs.test-dirs }}
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Find test directories
+        id: test-dirs
+        run: |
+          cd app/tests/ble
+          export TESTS=$(ls -d * | grep -v central | jq -R -s -c 'split("\n")[:-1]')
+          echo "::set-output name=test-dirs::${TESTS}"
+  run-tests:
+    needs: collect-tests
+    strategy:
+      matrix:
+        test: ${{ fromJSON(needs.collect-tests.outputs.test-dirs) }}
+    runs-on: ubuntu-latest
+    container:
+      image: docker.io/zmkfirmware/zmk-build-arm:3.2
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Cache west modules
+        uses: actions/cache@v3.0.2
+        env:
+          cache-name: cache-zephyr-modules
+        with:
+          path: |
+            modules/
+            tools/
+            zephyr/
+            bootloader/
+          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('app/west.yml') }}
+          restore-keys: |
+            ${{ runner.os }}-build-${{ env.cache-name }}-
+            ${{ runner.os }}-build-
+            ${{ runner.os }}-
+        timeout-minutes: 2
+        continue-on-error: true
+      - name: Initialize workspace (west init)
+        run: west init -l app
+      - name: Enable babblesim group filter
+        run: west config manifest.group-filter -- +babblesim
+      - name: Update modules (west update)
+        run: west update
+      - name: Export Zephyr CMake package (west zephyr-export)
+        run: west zephyr-export
+      - name: Build BabbleSim components
+        working-directory: tools/bsim
+        run: make everything
+      - name: Test ${{ matrix.test }}
+        working-directory: app
+        run: BSIM_COMPONENTS_PATH="${GITHUB_WORKSPACE}/tools/bsim/components/" BSIM_OUT_PATH="${GITHUB_WORKSPACE}/tools/bsim/" ./run-ble-test.sh tests/ble/${{ matrix.test }}
+      - name: Archive artifacts
+        if: ${{ always() }}
+        uses: actions/upload-artifact@v2
+        with:
+          name: "log-files"
+          path: app/build/**/*.log
diff --git a/.github/workflows/build-user-config.yml b/.github/workflows/build-user-config.yml
index c1a97b4d..7efa6425 100644
--- a/.github/workflows/build-user-config.yml
+++ b/.github/workflows/build-user-config.yml
@@ -52,18 +52,39 @@ jobs:
       fail-fast: false
       matrix: ${{ fromJson(needs.matrix.outputs.build_matrix) }}
     steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+
+      - name: Create build directory
+        run: |
+          echo "build_dir=$(mktemp -d)" >> $GITHUB_ENV
+
       - name: Prepare variables
         shell: sh -x {0}
         env:
+          board: ${{ matrix.board }}
           shield: ${{ matrix.shield }}
+          artifact_name: ${{ matrix.artifact-name }}
         run: |
-          echo "zephyr_version=${ZEPHYR_VERSION}" >> $GITHUB_ENV
-          echo "extra_cmake_args=${shield:+-DSHIELD=\"$shield\"}" >> $GITHUB_ENV
-          echo "display_name=${shield:+$shield - }${{ matrix.board }}" >> $GITHUB_ENV
-          echo "artifact_name=${shield:+$shield-}${{ matrix.board }}-zmk" >> $GITHUB_ENV
+          if [ -e zephyr/module.yml ]; then
+            export zmk_load_arg=" -DZMK_EXTRA_MODULES='${GITHUB_WORKSPACE}'"
+            export new_tmp_dir=$(mktemp -d)
+            echo "base_dir=${new_tmp_dir}" >> $GITHUB_ENV
+          else
+            echo "base_dir=${GITHUB_WORKSPACE}" >> $GITHUB_ENV
+          fi
 
-      - name: Checkout
-        uses: actions/checkout@v3
+          echo "zephyr_version=${ZEPHYR_VERSION}" >> $GITHUB_ENV
+          echo "extra_cmake_args=${shield:+-DSHIELD=\"$shield\"}${zmk_load_arg}" >> $GITHUB_ENV
+          echo "display_name=${shield:+$shield - }${board}" >> $GITHUB_ENV
+          echo "artifact_name=${artifact_name:-${shield:+$shield-}${board}-zmk}" >> $GITHUB_ENV
+
+      - name: Copy config files to isolated temporary directory
+        run: |
+          if [ "${{ env.base_dir }}" != "${GITHUB_WORKSPACE}" ]; then
+            mkdir "${{ env.base_dir }}/${{ inputs.config_path }}"
+            cp -R ${{ inputs.config_path }}/* "${{ env.base_dir }}/${{ inputs.config_path }}/"
+          fi
 
       - name: Cache west modules
         uses: actions/cache@v3.0.11
@@ -72,11 +93,11 @@ jobs:
           cache_name: cache-zephyr-${{ env.zephyr_version }}-modules
         with:
           path: |
-            modules/
-            tools/
-            zephyr/
-            bootloader/
-            zmk/
+            ${{ env.base_dir }}/modules/
+            ${{ env.base_dir }}/tools/
+            ${{ env.base_dir }}/zephyr/
+            ${{ env.base_dir }}/bootloader/
+            ${{ env.base_dir }}/zmk/
           key: ${{ runner.os }}-build-${{ env.cache_name }}-${{ hashFiles('**/west.yml', '**/build.yaml') }}
           restore-keys: |
             ${{ runner.os }}-build-${{ env.cache_name }}-
@@ -84,23 +105,27 @@ jobs:
             ${{ runner.os }}-
 
       - name: West Init
-        run: west init -l "${{ inputs.config_path }}"
+        working-directory: ${{ env.base_dir }}
+        run: west init -l "${{ env.base_dir }}/${{ inputs.config_path }}"
 
       - name: West Update
+        working-directory: ${{ env.base_dir }}
         run: west update
 
       - name: West Zephyr export
+        working-directory: ${{ env.base_dir }}
         run: west zephyr-export
 
       - name: West Build (${{ env.display_name }})
+        working-directory: ${{ env.base_dir }}
         shell: sh -x {0}
-        run: west build -s zmk/app -b "${{ matrix.board }}" -- -DZMK_CONFIG="${GITHUB_WORKSPACE}/${{ inputs.config_path }}" ${{ env.extra_cmake_args }} ${{ matrix.cmake-args }}
+        run: west build -s zmk/app -d "${{ env.build_dir }}" -b "${{ matrix.board }}" -- -DZMK_CONFIG=${{ env.base_dir }}/${{ inputs.config_path }} ${{ env.extra_cmake_args }} ${{ matrix.cmake-args }}
 
       - name: ${{ env.display_name }} Kconfig file
         run: |
-          if [ -f build/zephyr/.config ]
+          if [ -f "${{ env.build_dir }}/zephyr/.config" ]
           then
-            grep -v -e "^#" -e "^$" build/zephyr/.config | sort
+            grep -v -e "^#" -e "^$" "${{ env.build_dir }}/zephyr/.config" | sort
           else
             echo "No Kconfig output"
           fi
@@ -108,12 +133,12 @@ jobs:
 
       - name: ${{ env.display_name }} Devicetree file
         run: |
-          if [ -f build/zephyr/zephyr.dts ]
+          if [ -f "${{ env.build_dir }}/zephyr/zephyr.dts" ]
           then
-            cat build/zephyr/zephyr.dts
-          elif [ -f build/zephyr/zephyr.dts.pre ]
+            cat "${{ env.build_dir }}/zephyr/zephyr.dts"
+          elif [ -f "${{ env.build_dir }}/zephyr/zephyr.dts.pre" ]
           then
-            cat -s build/zephyr/zephyr.dts.pre
+            cat -s "${{ env.build_dir }}/zephyr/zephyr.dts.pre"
           else
             echo "No Devicetree output"
           fi
@@ -122,17 +147,17 @@ jobs:
       - name: Rename artifacts
         shell: sh -x {0}
         run: |
-          mkdir build/artifacts
-          if [ -f build/zephyr/zmk.uf2 ]
+          mkdir "${{ env.build_dir }}/artifacts"
+          if [ -f "${{ env.build_dir }}/zephyr/zmk.uf2" ]
           then
-            cp build/zephyr/zmk.uf2 "build/artifacts/${{ env.artifact_name }}.uf2"
-          elif [ -f build/zephyr/zmk.${{ inputs.fallback_binary }} ]
+            cp "${{ env.build_dir }}/zephyr/zmk.uf2" "${{ env.build_dir }}/artifacts/${{ env.artifact_name }}.uf2"
+          elif [ -f "${{ env.build_dir }}/zephyr/zmk.${{ inputs.fallback_binary }}" ]
           then
-            cp "build/zephyr/zmk.${{ inputs.fallback_binary }}" "build/artifacts/${{ env.artifact_name }}.${{ inputs.fallback_binary }}"
+            cp "${{ env.build_dir }}/zephyr/zmk.${{ inputs.fallback_binary }}" "${{ env.build_dir }}/artifacts/${{ env.artifact_name }}.${{ inputs.fallback_binary }}"
           fi
 
       - name: Archive (${{ env.display_name }})
         uses: actions/upload-artifact@v3
         with:
           name: ${{ inputs.archive_name }}
-          path: build/artifacts
+          path: ${{ env.build_dir }}/artifacts
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index e8a9d220..ec630812 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -24,7 +24,7 @@ jobs:
         id: test-dirs
         run: |
           cd app/tests/
-          export TESTS=$(ls -d * | jq -R -s -c 'split("\n")[:-1]')
+          export TESTS=$(ls -d * | grep -v ble | jq -R -s -c 'split("\n")[:-1]')
           echo "::set-output name=test-dirs::${TESTS}"
   run-tests:
     needs: collect-tests
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 0891364b..40c654db 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -2,19 +2,13 @@ cmake_minimum_required(VERSION 3.13.1)
 
 set(CONFIG_APPLICATION_DEFINED_SYSCALL true)
 
-# Add our custom Zephyr module for drivers w/ syscalls, etc.
-list(APPEND DTS_ROOT ${CMAKE_SOURCE_DIR}/drivers/zephyr)
-
-set(ZephyrBuildConfiguration_ROOT ${CMAKE_SOURCE_DIR}/cmake)
-
-list(APPEND ZEPHYR_EXTRA_MODULES
-  ${CMAKE_CURRENT_SOURCE_DIR}/module
-)
+set(ZEPHYR_EXTRA_MODULES "${ZMK_EXTRA_MODULES};${CMAKE_CURRENT_SOURCE_DIR}/module;${CMAKE_CURRENT_SOURCE_DIR}/keymap-module")
 
 # Find Zephyr. This also loads Zephyr's build system.
 find_package(Zephyr REQUIRED HINTS ../zephyr)
 project(zmk)
 
+zephyr_linker_sources(SECTIONS include/linker/zmk-behaviors.ld)
 zephyr_linker_sources(RODATA include/linker/zmk-events.ld)
 
 # Add your source file to the "app" target. This must come after
@@ -22,6 +16,7 @@ zephyr_linker_sources(RODATA include/linker/zmk-events.ld)
 target_include_directories(app PRIVATE include)
 target_sources(app PRIVATE src/stdlib.c)
 target_sources(app PRIVATE src/activity.c)
+target_sources(app PRIVATE src/behavior.c)
 target_sources(app PRIVATE src/kscan.c)
 target_sources(app PRIVATE src/matrix_transform.c)
 target_sources(app PRIVATE src/sensors.c)
@@ -68,6 +63,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
   target_sources(app PRIVATE src/events/layer_state_changed.c)
   target_sources(app PRIVATE src/events/modifiers_state_changed.c)
   target_sources(app PRIVATE src/events/keycode_state_changed.c)
+  target_sources_ifdef(CONFIG_ZMK_HID_INDICATORS app PRIVATE src/hid_indicators.c)
 
   if (CONFIG_ZMK_BLE)
     target_sources(app PRIVATE src/events/ble_active_profile_changed.c)
@@ -83,6 +79,8 @@ target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/behaviors/behavior_bac
 target_sources_ifdef(CONFIG_ZMK_BATTERY_REPORTING app PRIVATE src/events/battery_state_changed.c)
 target_sources_ifdef(CONFIG_ZMK_BATTERY_REPORTING app PRIVATE src/battery.c)
 
+target_sources_ifdef(CONFIG_ZMK_HID_INDICATORS app PRIVATE src/events/hid_indicators_changed.c)
+
 target_sources_ifdef(CONFIG_ZMK_SPLIT app PRIVATE src/events/split_peripheral_status_changed.c)
 add_subdirectory(src/split)
 
diff --git a/app/Kconfig b/app/Kconfig
index f92f0ae3..a9b1b39e 100644
--- a/app/Kconfig
+++ b/app/Kconfig
@@ -53,10 +53,19 @@ config ZMK_HID_REPORT_TYPE_NKRO
     help
       Enable full N-Key Roll Over for HID output. This selection will prevent the keyboard
       from working with some BIOS/UEFI versions that only support "boot keyboard" support.
-      This option also prevents using some infrequently used higher range HID usages.
+      This option also prevents using some infrequently used higher range HID usages (notably F13-F24 and INTL1-9)
+      These usages can be re enabled with ZMK_HID_KEYBOARD_NKRO_EXTENDED_REPORT.
 
 endchoice
 
+config ZMK_HID_KEYBOARD_NKRO_EXTENDED_REPORT
+    bool "Enable extended NKRO reporting"
+    depends on ZMK_HID_REPORT_TYPE_NKRO
+    help
+      Enables higher usage range for NKRO (F13-F24 and INTL1-9).
+      Please note this is not compatible with Android currently and you will get no input
+
+
 if ZMK_HID_REPORT_TYPE_HKRO
 
 config ZMK_HID_KEYBOARD_REPORT_SIZE
@@ -87,6 +96,12 @@ config ZMK_HID_CONSUMER_REPORT_USAGES_BASIC
 
 endchoice
 
+config ZMK_HID_INDICATORS
+    bool "HID Indicators"
+    help
+      Enable HID indicators, used for detecting state of Caps/Scroll/Num Lock,
+      Kata, and Compose.
+
 menu "Output Types"
 
 config ZMK_USB
@@ -121,21 +136,40 @@ menuconfig ZMK_BLE
     select BT_SMP_APP_PAIRING_ACCEPT
     select BT_PERIPHERAL
     select BT_DIS
-    select BT_SETTINGS
-    select SETTINGS
-    imply ZMK_BATTERY_REPORTING
+    imply BT_SETTINGS if !ARCH_POSIX
+    imply SETTINGS if !ARCH_POSIX
+    imply ZMK_BATTERY_REPORTING if !ARCH_POSIX
 
 if ZMK_BLE
 
+config ZMK_BLE_EXPERIMENTAL_FEATURES
+    bool "Experimental: Enable experimental/advanced BLE settings/features"
+    imply ZMK_BLE_PASSKEY_ENTRY
+    imply BT_GATT_AUTO_SEC_REQ
+    imply BT_SMP_ALLOW_UNAUTH_OVERWRITE
+    help
+      Enables a combination of settings that are planned to be default in future versions of ZMK.
+      This includes changes to timing on BLE pairing initation, BT Secure Connection passkey entry,
+      restores use of the updated/new LLCP implementation, disables 2M PHY support, and allows
+      overwrite of keys from previously paired hosts.
+
+config ZMK_BLE_PASSKEY_ENTRY
+    bool "Require passkey entry on the keyboard to complete pairing"
+    default n
+    select RING_BUFFER
+
+choice BT_LL_SW_LLCP_IMPL
+    default BT_LL_SW_LLCP_LEGACY if !ZMK_BLE_EXPERIMENTAL_FEATURES
+
+endchoice
+
+config BT_CTLR_PHY_2M
+    default n if ZMK_BLE_EXPERIMENTAL_FEATURES
+
 # BT_TINYCRYPT_ECC is required for BT_SMP_SC_PAIR_ONLY when using HCI
 config BT_TINYCRYPT_ECC
     default y if BT_HCI && !BT_CTLR
 
-choice BT_LL_SW_LLCP_IMPL
-    default BT_LL_SW_LLCP_LEGACY
-
-endchoice
-
 config SYSTEM_WORKQUEUE_STACK_SIZE
     default 4096 if SOC_RP2040
     default 2048
@@ -174,11 +208,6 @@ config BT_GATT_AUTO_SEC_REQ
 config BT_DEVICE_APPEARANCE
     default 961
 
-config ZMK_BLE_PASSKEY_ENTRY
-    bool "Require passkey entry on the keyboard to complete pairing"
-    default n
-    select RING_BUFFER
-
 config BT_PERIPHERAL_PREF_MIN_INT
     default 6
 
diff --git a/app/boards/arm/adv360pro/Kconfig b/app/boards/arm/adv360pro/Kconfig
new file mode 100644
index 00000000..1840851c
--- /dev/null
+++ b/app/boards/arm/adv360pro/Kconfig
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: MIT
+
+config BOARD_ENABLE_DCDC
+    bool "Enable DCDC mode"
+    select SOC_DCDC_NRF52X
+    default y
+    depends on BOARD_ADV360PRO_LEFT || BOARD_ADV360PRO_RIGHT
diff --git a/app/boards/arm/adv360pro/Kconfig.board b/app/boards/arm/adv360pro/Kconfig.board
new file mode 100644
index 00000000..51ebaec0
--- /dev/null
+++ b/app/boards/arm/adv360pro/Kconfig.board
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2023 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+#
+
+config BOARD_ADV360PRO_LEFT
+    bool "adv360pro_left"
+    depends on SOC_NRF52840_QIAA
+
+config BOARD_ADV360PRO_RIGHT
+    bool "adv360pro_right"
+    depends on SOC_NRF52840_QIAA
diff --git a/app/boards/arm/adv360pro/Kconfig.defconfig b/app/boards/arm/adv360pro/Kconfig.defconfig
new file mode 100644
index 00000000..0c4abacf
--- /dev/null
+++ b/app/boards/arm/adv360pro/Kconfig.defconfig
@@ -0,0 +1,55 @@
+#
+# Copyright (c) 2023 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+#
+
+if BOARD_ADV360PRO_LEFT
+
+config ZMK_KEYBOARD_NAME
+    default "Adv360 Pro"
+
+config ZMK_SPLIT_ROLE_CENTRAL
+    default y
+
+endif # BOARD_ADV360PRO_LEFT
+
+if BOARD_ADV360PRO_RIGHT
+
+config ZMK_KEYBOARD_NAME
+    default "Adv360 Pro rt"
+
+endif # BOARD_ADV360PRO_RIGHT
+
+
+if BOARD_ADV360PRO_LEFT || BOARD_ADV360PRO_RIGHT
+
+config BOARD
+    default "adv360pro"
+
+config ZMK_SPLIT
+    default y
+
+config SPI
+    bool
+    default y
+
+config BT_CTLR
+    default BT
+
+if USB
+
+config USB_NRFX
+    default y
+
+config USB_DEVICE_STACK
+    default y
+
+endif # USB
+
+config ZMK_BATTERY_VOLTAGE_DIVIDER
+    default y
+
+config SPI
+    default y
+
+endif # BOARD_ADV360PRO_LEFT || BOARD_ADV360PRO_RIGHT
diff --git a/app/boards/arm/adv360pro/README.md b/app/boards/arm/adv360pro/README.md
new file mode 100755
index 00000000..89fa1da5
--- /dev/null
+++ b/app/boards/arm/adv360pro/README.md
@@ -0,0 +1,7 @@
+# Kinesis Advantage 360 Professional
+
+This board definition provides upstream support for the [Kinesis Advantage 360 Professional](https://kinesis-ergo.com/keyboards/advantage360/)
+
+Kinesis offer a specific [custom configuration](https://github.com/KinesisCorporation/Adv360-Pro-ZMK/) for the 360 Pro that references [a customised version of ZMK](https://github.com/ReFil/zmk/tree/adv360-z3.2-2) with Advantage 360 Pro specific functionality and changes over base ZMK. The Kinesis fork is regularly updated to bring the latest updates and changes from base ZMK however will not always be completely up to date, some features such as new keycodes will not be immediately available on the 360 Pro after they are implemented in base ZMK.
+
+When using this board definition some of the more advanced features (the indicator RGB leds) will not work, and Kinesis cannot provide customer service for usage of base ZMK. Likewise the ZMK community cannot provide support for either the Kinesis keymap editor, nor any usage of the Kinesis custom fork.
diff --git a/app/boards/arm/adv360pro/adv360pro-pinctrl.dtsi b/app/boards/arm/adv360pro/adv360pro-pinctrl.dtsi
new file mode 100644
index 00000000..7dafcdce
--- /dev/null
+++ b/app/boards/arm/adv360pro/adv360pro-pinctrl.dtsi
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2023 The ZMK Contributors
+ * SPDX-License-Identifier: MIT
+ */
+
+&pinctrl {
+    spi3_default: spi3_default {
+        group1 {
+            psels = <NRF_PSEL(SPIM_MOSI, 0, 20)>;
+        };
+    };
+
+    spi3_sleep: spi3_sleep {
+        group1 {
+            psels = <NRF_PSEL(SPIM_MOSI, 0, 20)>;
+            low-power-enable;
+        };
+    };
+    pwm0_default: pwm0_default {
+        group1 {
+            psels = <NRF_PSEL(PWM_OUT0, 0, 17)>;
+        };
+    };
+    pwm0_sleep: pwm0_sleep {
+        group1 {
+            psels = <NRF_PSEL(PWM_OUT0, 0, 17)>;
+            low-power-enable;
+        };
+    };
+};
\ No newline at end of file
diff --git a/app/boards/arm/adv360pro/adv360pro.dtsi b/app/boards/arm/adv360pro/adv360pro.dtsi
new file mode 100644
index 00000000..c837e518
--- /dev/null
+++ b/app/boards/arm/adv360pro/adv360pro.dtsi
@@ -0,0 +1,157 @@
+/*
+*
+* Copyright (c) 2023 The ZMK Contributors
+* SPDX-License-Identifier: MIT
+*
+*/
+
+/dts-v1/;
+#include <nordic/nrf52840_qiaa.dtsi>
+
+#include <dt-bindings/led/led.h>
+#include <dt-bindings/zmk/matrix_transform.h>
+
+#include "adv360pro-pinctrl.dtsi"
+
+/ {
+    model = "Adv360 Pro";
+    compatible = "kinesis,adv360pro";
+
+    chosen {
+        zephyr,code-partition = &code_partition;
+        zephyr,sram = &sram0;
+        zephyr,flash = &flash0;
+        zephyr,console = &cdc_acm_uart;
+        zmk,kscan = &kscan0;
+        zmk,backlight = &backlight;
+        zmk,battery = &vbatt;
+        zmk,matrix_transform = &default_transform;
+        zmk,underglow = &led_strip;
+    };
+
+    default_transform: keymap_transform_0 {
+        compatible = "zmk,matrix-transform";
+        columns = <20>;
+        rows = <5>;
+
+
+        map = <
+            RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5)  RC(4,6)                                                                        RC(4,13) RC(4,14) RC(4,15) RC(4,16) RC(4,17) RC(4,18) RC(4,19)
+            RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5)  RC(3,6)                                                                        RC(3,13) RC(3,14) RC(3,15) RC(3,16) RC(3,17) RC(3,18) RC(3,19)
+            RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5)  RC(2,6)           RC(2,8)  RC(2,9)            RC(2,10) RC(2,11)                RC(2,13) RC(2,14) RC(2,15) RC(2,16) RC(2,17) RC(2,18) RC(2,19)
+            RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5)                             RC(1,9)            RC(1,10)                                  RC(1,14) RC(1,15) RC(1,16) RC(1,17) RC(1,18) RC(1,19)
+            RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4)                     RC(0,7) RC(0,8) RC(0,9)            RC(0,10) RC(0,11) RC(0,12)                         RC(0,15) RC(0,16) RC(0,17) RC(0,18) RC(0,19)
+
+        >;
+    };
+    ext-power {
+        compatible = "zmk,ext-power-generic";
+        control-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
+    };
+
+    vbatt: vbatt {
+        compatible = "zmk,battery-voltage-divider";
+        io-channels = <&adc 2>;
+        output-ohms = <100000>;
+        full-ohms = <(100000 + 100000)>;
+    };
+
+    backlight: pwmleds {
+        compatible = "pwm-leds";
+        pwm_led_0 {
+            pwms = <&pwm0 0 10000 PWM_POLARITY_NORMAL>;
+        };
+    };
+
+};
+
+&pwm0 {
+    status = "okay";
+    pinctrl-0 = <&pwm0_default>;
+    pinctrl-1 = <&pwm0_sleep>;
+    pinctrl-names = "default", "sleep";
+};
+
+&adc {
+    status = "okay";
+};
+
+&gpiote {
+    status = "okay";
+};
+
+&gpio0 {
+    status = "okay";
+};
+
+&gpio1 {
+    status = "okay";
+};
+
+&usbd {
+    status = "okay";
+    cdc_acm_uart: cdc_acm_uart {
+        compatible = "zephyr,cdc-acm-uart";
+    };
+};
+
+&flash0 {
+    /*
+     * For more information, see:
+     * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html
+     */
+    partitions {
+        compatible = "fixed-partitions";
+        #address-cells = <1>;
+        #size-cells = <1>;
+
+        sd_partition: partition@0 {
+            reg = <0x00000000 0x00026000>;
+        };
+        code_partition: partition@26000 {
+            reg = <0x00026000 0x000c6000>;
+        };
+
+        /*
+         * The flash starting at 0x000ec000 and ending at
+         * 0x000f3fff is reserved for use by the application.
+         */
+
+        /*
+         * Storage partition will be used by FCB/LittleFS/NVS
+         * if enabled.
+         */
+        storage_partition: partition@ec000 {
+            reg = <0x000ec000 0x00008000>;
+        };
+
+        boot_partition: partition@f4000 {
+            reg = <0x000f4000 0x0000c000>;
+        };
+    };
+};
+
+&spi3 {
+    compatible = "nordic,nrf-spim";
+    status = "okay";
+    pinctrl-0 = <&spi3_default>;
+    pinctrl-1 = <&spi3_sleep>;
+    pinctrl-names = "default", "sleep";
+
+    led_strip: ws2812@0 {
+        compatible = "worldsemi,ws2812-spi";
+
+        /* SPI */
+        reg = <0>;
+        spi-max-frequency = <4000000>;
+
+        /* WS2812 */
+        chain-length = <3>; /* number of LEDs */
+        spi-one-frame = <0x70>;
+        spi-zero-frame = <0x40>;
+
+        color-mapping = <LED_COLOR_ID_GREEN
+                        LED_COLOR_ID_RED
+                        LED_COLOR_ID_BLUE>;
+    };
+};
diff --git a/app/boards/arm/adv360pro/adv360pro.keymap b/app/boards/arm/adv360pro/adv360pro.keymap
new file mode 100644
index 00000000..999781e4
--- /dev/null
+++ b/app/boards/arm/adv360pro/adv360pro.keymap
@@ -0,0 +1,48 @@
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/rgb.h>
+#include <dt-bindings/zmk/backlight.h>
+
+/ {
+    keymap {
+        compatible = "zmk,keymap";
+
+        default_layer {
+            bindings = <
+                &kp EQUAL &kp N1    &kp N2   &kp N3   &kp N4     &kp N5 &tog 1                                                           &mo 3 &kp N6 &kp N7 &kp N8    &kp N9   &kp N0   &kp MINUS
+                &kp TAB   &kp Q     &kp W    &kp E    &kp R      &kp T  &none                                                            &none &kp Y  &kp U  &kp I     &kp O    &kp P    &kp BSLH
+                &kp ESC   &kp A     &kp S    &kp D    &kp F      &kp G  &none           &kp LCTRL &kp LALT &kp LGUI  &kp RCTRL           &none &kp H  &kp J  &kp K     &kp L    &kp SEMI &kp SQT
+                &kp LSHFT &kp Z     &kp X    &kp C    &kp V      &kp B                            &kp HOME &kp PG_UP                           &kp N  &kp M  &kp COMMA &kp DOT  &kp FSLH &kp RSHFT
+                &mo 2     &kp GRAVE &kp CAPS &kp LEFT &kp RIGHT                &kp BSPC &kp DEL   &kp END  &kp PG_DN &kp ENTER &kp SPACE              &kp UP &kp DOWN  &kp LBKT &kp RBKT &mo 2
+            >;
+        };
+        keypad {
+            bindings = <
+                &kp EQUAL &kp N1    &kp N2   &kp N3   &kp N4     &kp N5 &trans                                                           &mo 3 &kp N6 &kp KP_NUM &kp KP_EQUAL &kp KP_DIVIDE &kp KP_MULTIPLY &kp MINUS
+                &kp TAB   &kp Q     &kp W    &kp E    &kp R      &kp T  &none                                                            &none &kp Y  &kp KP_N7  &kp KP_N8    &kp KP_N9     &kp KP_MINUS    &kp BSLH
+                &kp ESC   &kp A     &kp S    &kp D    &kp F      &kp G  &none           &kp LCTRL &kp LALT &kp LGUI  &kp RCTRL           &none &kp H  &kp KP_N4  &kp KP_N5    &kp KP_N6     &kp KP_PLUS     &kp SQT
+                &kp LSHFT &kp Z     &kp X    &kp C    &kp V      &kp B                            &kp HOME &kp PG_UP                           &kp N  &kp KP_N1  &kp KP_N2    &kp KP_N3     &kp KP_ENTER    &kp RSHFT
+                &mo 2     &kp GRAVE &kp CAPS &kp LEFT &kp RIGHT                &kp BSPC &kp DEL   &kp END  &kp PG_DN &kp ENTER &kp KP_N0              &kp UP     &kp DOWN     &kp KP_DOT    &kp RBKT        &mo 2
+            >;
+        };
+        fn {
+            bindings = <
+                &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &tog 1                                           &mo 3 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12
+                &trans &trans &trans &trans &trans &trans  &none                                           &none &trans &trans &trans &trans  &trans  &trans
+                &trans &trans &trans &trans &trans &trans  &none        &trans &trans &trans &trans        &none &trans &trans &trans &trans  &trans  &trans
+                &trans &trans &trans &trans &trans &trans                      &trans &trans                     &trans &trans &trans &trans  &trans  &trans
+                &trans &trans &trans &trans &trans               &trans &trans &trans &trans &trans &trans              &trans &trans &trans  &trans  &trans
+            >;
+        };
+        mod {
+            bindings = <
+                &none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &none                                                               &trans      &none &none      &none      &none &none &none
+                &none &none        &none        &none        &none        &none        &bootloader                                                         &bootloader &none &none      &none      &none &none &none
+                &none &none        &none        &none        &none        &none        &none             &none &none &bt BT_CLR &none                      &none       &none &none      &none      &none &none &none
+                &none &none        &none        &none        &none        &none                                &none &none                                             &none &none      &none      &none &none &none
+                &none &none        &none        &none        &none                                 &none &none &none &none      &bl BL_TOG &rgb_ug RGB_TOG                   &bl BL_INC &bl BL_DEC &none &none &none
+            >;
+        };
+    };
+};
diff --git a/app/boards/arm/adv360pro/adv360pro.yaml b/app/boards/arm/adv360pro/adv360pro.yaml
new file mode 100644
index 00000000..2d555d4e
--- /dev/null
+++ b/app/boards/arm/adv360pro/adv360pro.yaml
@@ -0,0 +1,19 @@
+identifier: adv360pro
+name: Advantage 360 Pro
+type: keyboard
+arch: arm
+toolchain:
+  - zephyr
+  - gnuarmemb
+  - xtools
+supported:
+  - gpio
+  - i2c
+  - counter
+  - spi
+  - usb_device
+  - nvs
+  - can
+  - kscan
+  - ble
+  - pwm
diff --git a/app/boards/arm/adv360pro/adv360pro.zmk.yml b/app/boards/arm/adv360pro/adv360pro.zmk.yml
new file mode 100644
index 00000000..7d4a4b44
--- /dev/null
+++ b/app/boards/arm/adv360pro/adv360pro.zmk.yml
@@ -0,0 +1,16 @@
+file_format: "1"
+id: adv360pro
+name: Advantage 360 Pro
+type: board
+url: https://kinesis-ergo.com/keyboards/advantage360
+arch: arm
+features:
+  - keys
+  - underglow
+  - backlight
+outputs:
+  - usb
+  - ble
+siblings:
+  - adv360pro_left
+  - adv360pro_right
diff --git a/app/boards/arm/adv360pro/adv360pro_left.dts b/app/boards/arm/adv360pro/adv360pro_left.dts
new file mode 100644
index 00000000..6ef5f590
--- /dev/null
+++ b/app/boards/arm/adv360pro/adv360pro_left.dts
@@ -0,0 +1,36 @@
+/*
+*
+* Copyright (c) 2023 The ZMK Contributors
+* SPDX-License-Identifier: MIT
+*
+*/
+
+#include "adv360pro.dtsi"
+
+/{
+    kscan0: kscan {
+        compatible = "zmk,kscan-gpio-matrix";
+
+        diode-direction = "col2row";
+        row-gpios
+            = <&gpio1 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+            , <&gpio1 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+            , <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+            , <&gpio1 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+            , <&gpio1 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+            ;
+
+        col-gpios
+            = <&gpio0 25 GPIO_ACTIVE_HIGH>
+            , <&gpio0 11 GPIO_ACTIVE_HIGH>
+            , <&gpio0 2 GPIO_ACTIVE_HIGH>
+            , <&gpio0 28 GPIO_ACTIVE_HIGH>
+            , <&gpio0 29 GPIO_ACTIVE_HIGH>
+            , <&gpio0 30 GPIO_ACTIVE_HIGH>
+            , <&gpio0 31 GPIO_ACTIVE_HIGH>
+            , <&gpio1 9 GPIO_ACTIVE_HIGH>
+            , <&gpio0 12 GPIO_ACTIVE_HIGH>
+            , <&gpio0 7 GPIO_ACTIVE_HIGH>
+            ;
+    };
+};
diff --git a/app/boards/arm/adv360pro/adv360pro_left_defconfig b/app/boards/arm/adv360pro/adv360pro_left_defconfig
new file mode 100644
index 00000000..6eb5a8d0
--- /dev/null
+++ b/app/boards/arm/adv360pro/adv360pro_left_defconfig
@@ -0,0 +1,55 @@
+#
+# Copyright (c) 2023 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+#
+
+CONFIG_SOC_SERIES_NRF52X=y
+CONFIG_SOC_NRF52840_QIAA=y
+CONFIG_BOARD_ADV360PRO_LEFT=y
+
+# Enable MPU
+CONFIG_ARM_MPU=y
+
+# enable GPIO
+CONFIG_GPIO=y
+
+# Enable SPI for LEDS
+CONFIG_PINCTRL=y
+CONFIG_SPI=y
+CONFIG_SPI_NRFX=y
+
+# Enable writing to flash
+CONFIG_USE_DT_CODE_PARTITION=y
+CONFIG_MPU_ALLOW_FLASH_WRITE=y
+CONFIG_NVS=y
+CONFIG_SETTINGS_NVS=y
+CONFIG_FLASH=y
+CONFIG_FLASH_PAGE_LAYOUT=y
+CONFIG_FLASH_MAP=y
+
+# Enable 32kHz crystal
+CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y
+CONFIG_CLOCK_CONTROL_NRF_K32SRC_150PPM=y
+
+#RGB leds config
+CONFIG_WS2812_STRIP=y
+CONFIG_ZMK_RGB_UNDERGLOW=y
+CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y
+CONFIG_ZMK_RGB_UNDERGLOW_ON_START=n
+CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=0
+CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE=y
+
+#Backlighting configuration
+CONFIG_PWM=y
+CONFIG_LED_PWM=y
+CONFIG_ZMK_BACKLIGHT=y
+CONFIG_ZMK_BACKLIGHT_BRT_START=20
+CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE=y
+
+#Misc configuration
+CONFIG_BT_CTLR_TX_PWR_PLUS_8=y
+CONFIG_ZMK_HID_REPORT_TYPE_NKRO=y
+CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC=y
+CONFIG_BUILD_OUTPUT_UF2=y
+CONFIG_ZMK_USB=y
+CONFIG_ZMK_BLE=y
diff --git a/app/boards/arm/adv360pro/adv360pro_right.dts b/app/boards/arm/adv360pro/adv360pro_right.dts
new file mode 100644
index 00000000..97d846f8
--- /dev/null
+++ b/app/boards/arm/adv360pro/adv360pro_right.dts
@@ -0,0 +1,40 @@
+/*
+*
+* Copyright (c) 2023 The ZMK Contributors
+* SPDX-License-Identifier: MIT
+*
+*/
+
+#include "adv360pro.dtsi"
+
+/{
+    kscan0: kscan {
+        compatible = "zmk,kscan-gpio-matrix";
+
+        diode-direction = "col2row";
+        row-gpios
+            = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+            , <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+            , <&gpio0 31 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+            , <&gpio0 30 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+            , <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+            ;
+
+        col-gpios
+            = <&gpio0  12 GPIO_ACTIVE_HIGH>
+            , <&gpio1  9 GPIO_ACTIVE_HIGH>
+            , <&gpio0  7 GPIO_ACTIVE_HIGH>
+            , <&gpio1  11 GPIO_ACTIVE_HIGH>
+            , <&gpio1  10 GPIO_ACTIVE_HIGH>
+            , <&gpio1  13 GPIO_ACTIVE_HIGH>
+            , <&gpio1  15 GPIO_ACTIVE_HIGH>
+            , <&gpio0 3 GPIO_ACTIVE_HIGH>
+            , <&gpio0 2 GPIO_ACTIVE_HIGH>
+            , <&gpio0 28 GPIO_ACTIVE_HIGH>
+            ;
+    };
+};
+
+&default_transform {
+    col-offset = <10>;
+};
diff --git a/app/boards/arm/adv360pro/adv360pro_right_defconfig b/app/boards/arm/adv360pro/adv360pro_right_defconfig
new file mode 100644
index 00000000..b5174549
--- /dev/null
+++ b/app/boards/arm/adv360pro/adv360pro_right_defconfig
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2023 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+#
+
+CONFIG_SOC_SERIES_NRF52X=y
+CONFIG_SOC_NRF52840_QIAA=y
+CONFIG_BOARD_ADV360PRO_RIGHT=y
+
+# Enable MPU
+CONFIG_ARM_MPU=y
+
+# enable GPIO
+CONFIG_GPIO=y
+
+# Enable SPI for LEDS
+CONFIG_PINCTRL=y
+CONFIG_SPI=y
+CONFIG_SPI_NRFX=y
+
+# Enable writing to flash
+CONFIG_USE_DT_CODE_PARTITION=y
+CONFIG_MPU_ALLOW_FLASH_WRITE=y
+CONFIG_NVS=y
+CONFIG_SETTINGS_NVS=y
+CONFIG_FLASH=y
+CONFIG_FLASH_PAGE_LAYOUT=y
+CONFIG_FLASH_MAP=y
+
+# Enable 32kHz crystal
+CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y
+CONFIG_CLOCK_CONTROL_NRF_K32SRC_150PPM=y
+
+#RGB leds config
+CONFIG_WS2812_STRIP=y
+CONFIG_ZMK_RGB_UNDERGLOW=y
+CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y
+CONFIG_ZMK_RGB_UNDERGLOW_ON_START=n
+CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=0
+CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE=y
+
+#Backlighting configuration
+CONFIG_PWM=y
+CONFIG_LED_PWM=y
+CONFIG_ZMK_BACKLIGHT=y
+CONFIG_ZMK_BACKLIGHT_BRT_START=20
+CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE=y
+
+#Misc configuration
+CONFIG_BT_CTLR_TX_PWR_PLUS_8=y
+CONFIG_ZMK_HID_REPORT_TYPE_NKRO=y
+CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC=y
+CONFIG_BUILD_OUTPUT_UF2=y
+CONFIG_ZMK_BLE=y
diff --git a/app/boards/arm/adv360pro/board.cmake b/app/boards/arm/adv360pro/board.cmake
new file mode 100644
index 00000000..6d62a8a1
--- /dev/null
+++ b/app/boards/arm/adv360pro/board.cmake
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2023 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+#
+
+board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset")
+
+include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
diff --git a/app/boards/arm/bdn9/bdn9_rev2.dts b/app/boards/arm/bdn9/bdn9_rev2.dts
index 1b85067c..6e15408a 100644
--- a/app/boards/arm/bdn9/bdn9_rev2.dts
+++ b/app/boards/arm/bdn9/bdn9_rev2.dts
@@ -23,7 +23,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-direct";
-        label = "KSCAN";
 
         input-gpios
             = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
@@ -40,7 +39,6 @@
 
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&gpioa 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&gpioa 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -48,7 +46,6 @@
     };
     mid_encoder: encoder_mid {
         compatible = "alps,ec11";
-        label = "MID_ENCODER";
         a-gpios = <&gpioa 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&gpioa 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -56,7 +53,6 @@
     };
     right_encoder: encoder_right {
         compatible = "alps,ec11";
-        label = "RIGHT_ENCODER";
         a-gpios = <&gpioa 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&gpiob 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -78,7 +74,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
@@ -117,7 +112,6 @@
     pinctrl-names = "default";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -137,7 +131,6 @@
 
         /* Set 6Kb of storage at the end of the 128Kb of flash */
         storage_partition: partition@1e800 {
-            label = "storage";
             reg = <0x0001e800 0x00001800>;
         };
     };
diff --git a/app/boards/arm/bluemicro840/bluemicro840_v1.dts b/app/boards/arm/bluemicro840/bluemicro840_v1.dts
index 05849001..408cca3b 100644
--- a/app/boards/arm/bluemicro840/bluemicro840_v1.dts
+++ b/app/boards/arm/bluemicro840/bluemicro840_v1.dts
@@ -25,20 +25,18 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         init-delay-ms = <20>;
         control-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 7>;
         output-ohms = <2000000>;
         full-ohms = <(2000000 + 806000)>;
@@ -81,7 +79,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -97,11 +94,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -115,12 +110,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/bt60/bt60.dtsi b/app/boards/arm/bt60/bt60.dtsi
index 8a270250..68d817ea 100644
--- a/app/boards/arm/bt60/bt60.dtsi
+++ b/app/boards/arm/bt60/bt60.dtsi
@@ -32,7 +32,6 @@
 
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&gpio1 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&gpio1 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -44,13 +43,11 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 2>;
         output-ohms = <2000000>;
         full-ohms = <(2000000 + 806000)>;
@@ -89,7 +86,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -105,11 +101,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -123,12 +117,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/bt60/bt60_v1.dts b/app/boards/arm/bt60/bt60_v1.dts
index 0cfe184a..4f66a0c2 100644
--- a/app/boards/arm/bt60/bt60_v1.dts
+++ b/app/boards/arm/bt60/bt60_v1.dts
@@ -81,7 +81,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/arm/bt60/bt60_v1_hs.dts b/app/boards/arm/bt60/bt60_v1_hs.dts
index b24dee1e..155d626c 100644
--- a/app/boards/arm/bt60/bt60_v1_hs.dts
+++ b/app/boards/arm/bt60/bt60_v1_hs.dts
@@ -30,7 +30,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/arm/ckp/ckp.dtsi b/app/boards/arm/ckp/ckp.dtsi
index ec2bd6a8..6bbbbdd7 100644
--- a/app/boards/arm/ckp/ckp.dtsi
+++ b/app/boards/arm/ckp/ckp.dtsi
@@ -34,7 +34,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
@@ -66,15 +65,14 @@
             ;
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
     };
 
     encoder_1: encoder_1 {
         compatible = "alps,ec11";
-        label = "ENCODER_ONE";
         a-gpios = <&gpio0 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&gpio0 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -83,7 +81,6 @@
 
     encoder_2: encoder_2 {
         compatible = "alps,ec11";
-        label = "ENCODER_TWO";
         a-gpios = <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&gpio0 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -92,7 +89,6 @@
 
     encoder_3: encoder_3 {
         compatible = "alps,ec11";
-        label = "encoder_3";
         a-gpios = <&gpio0 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&gpio0 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -101,7 +97,6 @@
 
     backlight: pwmleds {
         compatible = "pwm-leds";
-        label = "Backlight LEDs";
         pwm_led_0 {
             pwms = <&pwm0 0 10000 PWM_POLARITY_NORMAL>;
         };
@@ -111,13 +106,11 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "VBATT";
         io-channels = <&adc 2>;
         output-ohms = <100000>;
         full-ohms = <(100000 + 100000)>;
@@ -163,11 +156,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -181,12 +172,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
@@ -201,7 +190,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>;
diff --git a/app/boards/arm/corneish_zen/corneish_zen.dtsi b/app/boards/arm/corneish_zen/corneish_zen.dtsi
index 289c5e73..c6f2b630 100644
--- a/app/boards/arm/corneish_zen/corneish_zen.dtsi
+++ b/app/boards/arm/corneish_zen/corneish_zen.dtsi
@@ -80,7 +80,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -95,11 +94,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -113,12 +110,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/corneish_zen/corneish_zen.keymap b/app/boards/arm/corneish_zen/corneish_zen.keymap
index 24c925e8..d2549819 100644
--- a/app/boards/arm/corneish_zen/corneish_zen.keymap
+++ b/app/boards/arm/corneish_zen/corneish_zen.keymap
@@ -21,7 +21,7 @@
         compatible = "zmk,keymap";
 
         default_layer {
-            label = "QWERTY";
+            display-name = "QWERTY";
 // --------------------------------------------------------------------------------
 // |  TAB |  Q  |  W  |  E  |  R  |  T  |   |  Y  |  U   |  I  |  O  |  P  | BKSP |
 // | CTRL |  A  |  S  |  D  |  F  |  G  |   |  H  |  J   |  K  |  L  |  ;  |  '   |
@@ -36,7 +36,7 @@
         };
 
         lower_layer {
-            label = "NUMBER";
+            display-name = "NUMBER";
 // -----------------------------------------------------------------------------------------
 // |  TAB |  1  |  2  |  3  |  4  |  5  |   |  6  |  7  |  8  |  9  |  0  | BKSP |
 // | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 |   | LFT | DWN |  UP | RGT |     |      |
@@ -51,7 +51,7 @@
         };
 
         raise_layer {
-            label = "SYMBOL";
+            display-name = "SYMBOL";
 // -----------------------------------------------------------------------------------------
 // |  TAB |  !  |  @  |  #  |  $  |  %  |   |  ^  |  &  |  *  |  (  |  )  | BKSP |
 // | CTRL |     |     |     |     |     |   |  -  |  =  |  [  |  ]  |  \  |  `   |
diff --git a/app/boards/arm/corneish_zen/corneish_zen_v1_left.dts b/app/boards/arm/corneish_zen/corneish_zen_v1_left.dts
index 399a564f..6683b1b2 100644
--- a/app/boards/arm/corneish_zen/corneish_zen_v1_left.dts
+++ b/app/boards/arm/corneish_zen/corneish_zen_v1_left.dts
@@ -15,7 +15,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -39,7 +38,6 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 };
@@ -88,7 +86,6 @@
 
     fuelgauge: bq274xx@55 {
         compatible = "ti,bq274xx";
-        label = "BATTERY";
         reg = <0x55>;
         design-voltage = <3700>; //Battery Design Volatge in mV
         design-capacity = <180>; //Battery Design Capacity in mAh
@@ -109,7 +106,6 @@
     epd: il0323@0 {
         compatible = "gooddisplay,il0323";
         reg =  <0>;
-        label = "DISPLAY";
         width = <80>;
         height = <128>;
         spi-max-frequency = <4000000>;
diff --git a/app/boards/arm/corneish_zen/corneish_zen_v1_right.dts b/app/boards/arm/corneish_zen/corneish_zen_v1_right.dts
index d5f6e588..492c79fa 100644
--- a/app/boards/arm/corneish_zen/corneish_zen_v1_right.dts
+++ b/app/boards/arm/corneish_zen/corneish_zen_v1_right.dts
@@ -15,7 +15,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -39,7 +38,6 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 };
@@ -96,7 +94,6 @@
 
     fuelgauge: bq274xx@55 {
         compatible = "ti,bq274xx";
-        label = "BATTERY";
         reg = <0x55>;
         design-voltage = <3700>; //Battery Design Volatge in mV
         design-capacity = <180>; //Battery Design Capacity in mAh
@@ -117,7 +114,6 @@
     epd: il0323@0 {
         compatible = "gooddisplay,il0323";
         reg =  <0>;
-        label = "DISPLAY";
         width = <80>;
         height = <128>;
         spi-max-frequency = <4000000>;
diff --git a/app/boards/arm/corneish_zen/corneish_zen_v2_left.dts b/app/boards/arm/corneish_zen/corneish_zen_v2_left.dts
index 14d82e87..dacb24c3 100644
--- a/app/boards/arm/corneish_zen/corneish_zen_v2_left.dts
+++ b/app/boards/arm/corneish_zen/corneish_zen_v2_left.dts
@@ -15,7 +15,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -39,13 +38,11 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 0>;
         output-ohms = <1960000>;
         full-ohms = <(1960000 + 810000)>;
@@ -83,7 +80,6 @@
     epd: il0323@0 {
         compatible = "gooddisplay,il0323";
         reg =  <0>;
-        label = "DISPLAY";
         width = <80>;
         height = <128>;
         spi-max-frequency = <4000000>;
diff --git a/app/boards/arm/corneish_zen/corneish_zen_v2_right.dts b/app/boards/arm/corneish_zen/corneish_zen_v2_right.dts
index 4d444cae..f1baea42 100644
--- a/app/boards/arm/corneish_zen/corneish_zen_v2_right.dts
+++ b/app/boards/arm/corneish_zen/corneish_zen_v2_right.dts
@@ -15,7 +15,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -39,13 +38,11 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 0>;
         output-ohms = <1960000>;
         full-ohms = <(1960000 + 810000)>;
@@ -90,7 +87,6 @@
     epd: il0323@0 {
         compatible = "gooddisplay,il0323";
         reg =  <0>;
-        label = "DISPLAY";
         width = <80>;
         height = <128>;
         spi-max-frequency = <4000000>;
diff --git a/app/boards/arm/corneish_zen/widgets/layer_status.c b/app/boards/arm/corneish_zen/widgets/layer_status.c
index 3dc33613..86418318 100644
--- a/app/boards/arm/corneish_zen/widgets/layer_status.c
+++ b/app/boards/arm/corneish_zen/widgets/layer_status.c
@@ -45,7 +45,7 @@ static void layer_status_update_cb(struct layer_status_state state) {
 
 static struct layer_status_state layer_status_get_state(const zmk_event_t *eh) {
     uint8_t index = zmk_keymap_highest_layer_active();
-    return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_label(index)};
+    return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_name(index)};
 }
 
 ZMK_DISPLAY_WIDGET_LISTENER(widget_layer_status, struct layer_status_state, layer_status_update_cb,
diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1.dts b/app/boards/arm/dz60rgb/dz60rgb_rev1.dts
index 14be837d..25c95ddf 100644
--- a/app/boards/arm/dz60rgb/dz60rgb_rev1.dts
+++ b/app/boards/arm/dz60rgb/dz60rgb_rev1.dts
@@ -36,7 +36,6 @@ RC(4,0)   RC(4,1)   RC(4,2)                      RC(4,5)                     RC(
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -70,7 +69,6 @@ RC(4,0)   RC(4,1)   RC(4,2)                      RC(4,5)                     RC(
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -86,7 +84,6 @@ RC(4,0)   RC(4,1)   RC(4,2)                      RC(4,5)                     RC(
 
         /* Set 6Kb of storage at the end of the 256Kb of flash */
         storage_partition: partition@3e800 {
-            label = "storage";
             reg = <0x0003e800 0x00001800>;
         };
     };
diff --git a/app/boards/arm/ferris/ferris_rev02.dts b/app/boards/arm/ferris/ferris_rev02.dts
index 618a5591..1b9408d2 100644
--- a/app/boards/arm/ferris/ferris_rev02.dts
+++ b/app/boards/arm/ferris/ferris_rev02.dts
@@ -40,7 +40,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-composite";
-        label = "KSCAN";
         rows = <4>;
         columns = <10>;
 
@@ -56,7 +55,6 @@
 
     kscan_left: kscan_left {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN_LEFT";
 
         diode-direction = "col2row";
 
@@ -77,7 +75,6 @@
 
     kscan_right: kscan_right {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN_RIGHT";
 
         diode-direction = "row2col";
 
@@ -117,7 +114,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -156,7 +152,6 @@
 
         /* Set 6Kb of storage at the end of the 128Kb of flash */
         storage_partition: partition@3e800 {
-            label = "storage";
             reg = <0x0001e800 0x00001800>;
         };
     };
diff --git a/app/boards/arm/ferris/ferris_rev02.keymap b/app/boards/arm/ferris/ferris_rev02.keymap
index 18fad423..dc298ec8 100644
--- a/app/boards/arm/ferris/ferris_rev02.keymap
+++ b/app/boards/arm/ferris/ferris_rev02.keymap
@@ -20,7 +20,6 @@
     behaviors {
         hm: homerow_mods {
             compatible = "zmk,behavior-hold-tap";
-            label = "homerow mods";
             #binding-cells = <2>;
             tapping_term_ms = <200>;
             flavor = "tap-preferred";
diff --git a/app/boards/arm/glove80/glove80.dtsi b/app/boards/arm/glove80/glove80.dtsi
index f3f58cf7..3e3a6233 100644
--- a/app/boards/arm/glove80/glove80.dtsi
+++ b/app/boards/arm/glove80/glove80.dtsi
@@ -34,7 +34,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
         debounce-press-ms = <4>;
         debounce-release-ms = <20>;
@@ -62,7 +61,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -77,11 +75,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -95,12 +91,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/glove80/glove80.keymap b/app/boards/arm/glove80/glove80.keymap
index 6c920ca1..60129bd9 100644
--- a/app/boards/arm/glove80/glove80.keymap
+++ b/app/boards/arm/glove80/glove80.keymap
@@ -22,7 +22,6 @@
         // Configure it as a tap dance, so the first tap (or hold) is a &mo and the second tap is a &to
         layer_td: tap_dance_0 {
             compatible = "zmk,behavior-tap-dance";
-            label = "LAYER_TAP_DANCE";
             #binding-cells = <0>;
             tapping-term-ms = <200>;
             bindings = <&mo LOWER>, <&to LOWER>;
@@ -31,7 +30,6 @@
 
     macros {
         bt_0: bt_profile_macro_0 {
-            label = "BT_0";
             compatible = "zmk,behavior-macro";
             #binding-cells = <0>;
             bindings
@@ -40,7 +38,6 @@
         };
 
         bt_1: bt_profile_macro_1 {
-            label = "BT_1";
             compatible = "zmk,behavior-macro";
             #binding-cells = <0>;
             bindings
@@ -49,7 +46,6 @@
         };
 
         bt_2: bt_profile_macro_2 {
-            label = "BT_2";
             compatible = "zmk,behavior-macro";
             #binding-cells = <0>;
             bindings
@@ -58,7 +54,6 @@
         };
 
         bt_3: bt_profile_macro_3 {
-            label = "BT_3";
             compatible = "zmk,behavior-macro";
             #binding-cells = <0>;
             bindings
diff --git a/app/boards/arm/glove80/glove80_lh.dts b/app/boards/arm/glove80/glove80_lh.dts
index ed40e0d2..5ef54207 100644
--- a/app/boards/arm/glove80/glove80_lh.dts
+++ b/app/boards/arm/glove80/glove80_lh.dts
@@ -21,23 +21,20 @@
 
     back_led_backlight: pwmleds {
         compatible = "pwm-leds";
-        label = "BACK LED";
         pwm_led_0 {
             pwms = <&pwm0 0 PWM_USEC(20) PWM_POLARITY_NORMAL>;
-            label = "Back LED configured as backlight";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; /* WS2812_CE */
         init-delay-ms = <100>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-nrf-vddh";
-        label = "BATTERY";
     };
 };
 
@@ -51,7 +48,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812C-2020";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/arm/glove80/glove80_rh.dts b/app/boards/arm/glove80/glove80_rh.dts
index 288f6368..6f108d74 100644
--- a/app/boards/arm/glove80/glove80_rh.dts
+++ b/app/boards/arm/glove80/glove80_rh.dts
@@ -22,23 +22,20 @@
 
     back_led_backlight: pwmleds {
         compatible = "pwm-leds";
-        label = "BACK LED";
         pwm_led_0 {
             pwms = <&pwm0 0 PWM_USEC(20) PWM_POLARITY_NORMAL>;
-            label = "Back LED configured as backlight";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>; /* WS2812_CE */
         init-delay-ms = <100>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-nrf-vddh";
-        label = "BATTERY";
     };
 };
 
@@ -52,7 +49,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812C-2020";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.dts b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.dts
index 261ffbf4..ae2f9521 100644
--- a/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.dts
+++ b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.dts
@@ -53,7 +53,6 @@ RC(4,0) RC(4,1) RC(4,2)                         RC(4,6)         RC(4,8) RC(4,9)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -93,7 +92,6 @@ RC(4,0) RC(4,1) RC(4,2)                         RC(4,6)         RC(4,8) RC(4,9)
 
         /* Reserved memory for the second stage bootloader */
         second_stage_bootloader: partition@0 {
-            label = "second_stage_bootloader";
             reg = <0x00000000 0x100>;
             read-only;
         };
@@ -103,7 +101,6 @@ RC(4,0) RC(4,1) RC(4,2)                         RC(4,6)         RC(4,8) RC(4,9)
          * size is 16MB minus the 0x100 bytes taken by the bootloader.
          */
         code_partition: partition@100 {
-            label = "code";
             reg = <0x100 (DT_SIZE_M(16) - 0x100)>;
             read-only;
         };
diff --git a/app/boards/arm/mikoto/mikoto_520.dts b/app/boards/arm/mikoto/mikoto_520.dts
index f8007033..05ec72df 100644
--- a/app/boards/arm/mikoto/mikoto_520.dts
+++ b/app/boards/arm/mikoto/mikoto_520.dts
@@ -25,20 +25,18 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
         init-delay-ms = <50>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 1>;
         output-ohms = <10000000>;
         full-ohms = <(10000000 + 4000000)>;
@@ -80,7 +78,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -96,11 +93,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -114,12 +109,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/nice60/nice60.dts b/app/boards/arm/nice60/nice60.dts
index 651dd555..63b9685d 100644
--- a/app/boards/arm/nice60/nice60.dts
+++ b/app/boards/arm/nice60/nice60.dts
@@ -42,7 +42,6 @@ RC(4,0)   RC(4,1)   RC(4,2)                      RC(4,5)                       R
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -74,19 +73,17 @@ RC(4,0)   RC(4,1)   RC(4,2)                      RC(4,5)                       R
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 2>;
         output-ohms = <2000000>;
         full-ohms = <(2000000 + 806000)>;
@@ -118,7 +115,6 @@ RC(4,0)   RC(4,1)   RC(4,2)                      RC(4,5)                       R
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
@@ -136,7 +132,6 @@ RC(4,0)   RC(4,1)   RC(4,2)                      RC(4,5)                       R
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -151,12 +146,10 @@ RC(4,0)   RC(4,1)   RC(4,2)                      RC(4,5)                       R
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "mbr";
             reg = <0x00000000 0x00001000>;
         };
 
         code_partition: partition@1000 {
-            label = "code_partition";
             reg = <0x00001000 0x000d3000>;
         };
 
@@ -170,12 +163,10 @@ RC(4,0)   RC(4,1)   RC(4,2)                      RC(4,5)                       R
          * if enabled.
          */
         storage_partition: partition@d4000 {
-            label = "storage";
             reg = <0x000d4000 0x00020000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/nice_nano/nice_nano.dts b/app/boards/arm/nice_nano/nice_nano.dts
index 4ee0df7f..06be88e1 100644
--- a/app/boards/arm/nice_nano/nice_nano.dts
+++ b/app/boards/arm/nice_nano/nice_nano.dts
@@ -12,15 +12,14 @@
         zmk,battery = &vbatt;
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 2>;
         output-ohms = <2000000>;
         full-ohms = <(2000000 + 806000)>;
diff --git a/app/boards/arm/nice_nano/nice_nano.dtsi b/app/boards/arm/nice_nano/nice_nano.dtsi
index 0c0a3823..81f10906 100644
--- a/app/boards/arm/nice_nano/nice_nano.dtsi
+++ b/app/boards/arm/nice_nano/nice_nano.dtsi
@@ -23,7 +23,6 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 };
@@ -63,7 +62,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -79,11 +77,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -97,12 +93,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/nice_nano/nice_nano_v2.dts b/app/boards/arm/nice_nano/nice_nano_v2.dts
index b2fbcc81..c4f7a821 100644
--- a/app/boards/arm/nice_nano/nice_nano_v2.dts
+++ b/app/boards/arm/nice_nano/nice_nano_v2.dts
@@ -12,15 +12,14 @@
         zmk,battery = &vbatt;
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
         init-delay-ms = <50>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-nrf-vddh";
-        label = "BATTERY";
     };
 };
diff --git a/app/boards/arm/nrf52840_m2/nrf52840_m2.dts b/app/boards/arm/nrf52840_m2/nrf52840_m2.dts
index 253e6b77..85e9ce21 100644
--- a/app/boards/arm/nrf52840_m2/nrf52840_m2.dts
+++ b/app/boards/arm/nrf52840_m2/nrf52840_m2.dts
@@ -23,21 +23,17 @@
         compatible = "gpio-leds";
         red_led: led_0 {
             gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
-            label = "Red LED";
         };
         green_led: led_1 {
             gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>;
-            label = "Green LED";
         };
         blue_led: led_2 {
             gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 0>;
         output-ohms = <1000000>;
         full-ohms = <(1000000 + 1000000)>;
@@ -66,7 +62,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -82,11 +77,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -100,12 +93,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/nrfmicro/nrfmicro_11.dts b/app/boards/arm/nrfmicro/nrfmicro_11.dts
index 14b9adb9..c0c02ee9 100644
--- a/app/boards/arm/nrfmicro/nrfmicro_11.dts
+++ b/app/boards/arm/nrfmicro/nrfmicro_11.dts
@@ -24,13 +24,12 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
     };
 };
@@ -66,7 +65,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -82,11 +80,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -100,12 +96,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts
index 874b67e2..df3b224b 100644
--- a/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts
+++ b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts
@@ -24,13 +24,12 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
     };
 };
@@ -66,7 +65,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -82,11 +80,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -100,12 +96,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/nrfmicro/nrfmicro_13.dts b/app/boards/arm/nrfmicro/nrfmicro_13.dts
index 65674132..f5ae81c9 100644
--- a/app/boards/arm/nrfmicro/nrfmicro_13.dts
+++ b/app/boards/arm/nrfmicro/nrfmicro_13.dts
@@ -25,19 +25,17 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 2>;
         output-ohms = <2000000>;
         full-ohms = <(2000000 + 820000)>;
@@ -79,7 +77,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -95,11 +92,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -113,12 +108,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/nrfmicro/nrfmicro_13_52833.dts b/app/boards/arm/nrfmicro/nrfmicro_13_52833.dts
index cfe77e37..d6c88692 100644
--- a/app/boards/arm/nrfmicro/nrfmicro_13_52833.dts
+++ b/app/boards/arm/nrfmicro/nrfmicro_13_52833.dts
@@ -25,19 +25,17 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 2>;
         output-ohms = <2000000>;
         full-ohms = <(2000000 + 820000)>;
@@ -79,7 +77,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -95,11 +92,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x00046000>;
         };
 
@@ -113,12 +108,10 @@
          * if enabled.
          */
         storage_partition: partition@6c000 {
-            label = "storage";
             reg = <0x0006c000 0x00008000>;
         };
 
         boot_partition: partition@74000 {
-            label = "adafruit_boot";
             reg = <0x00074000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/pillbug/pillbug.dts b/app/boards/arm/pillbug/pillbug.dts
index a2e56df3..c30d306e 100644
--- a/app/boards/arm/pillbug/pillbug.dts
+++ b/app/boards/arm/pillbug/pillbug.dts
@@ -26,20 +26,18 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
-            label = "Blue LED";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
         init-delay-ms = <50>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 2>;
         output-ohms = <2000000>;
         full-ohms = <(2000000 + 820000)>;
@@ -89,7 +87,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -105,12 +102,10 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "mbr";
             reg = <0x00000000 0x00001000>;
         };
 
         code_partition: partition@1000 {
-            label = "code_partition";
             reg = <0x00001000 0x000d3000>;
         };
 
@@ -124,12 +119,10 @@
          * if enabled.
          */
         storage_partition: partition@d4000 {
-            label = "storage";
             reg = <0x000d4000 0x00020000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/planck/planck_rev6.dts b/app/boards/arm/planck/planck_rev6.dts
index 5fdd2c21..0951d618 100644
--- a/app/boards/arm/planck/planck_rev6.dts
+++ b/app/boards/arm/planck/planck_rev6.dts
@@ -23,7 +23,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
                 diode-direction = "col2row";
         row-gpios
             = <&gpioa 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
@@ -89,7 +88,6 @@ layout_2x2u_transform:
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -125,7 +123,6 @@ layout_2x2u_transform:
 
         /* Set 6Kb of storage at the end of the 256Kb of flash */
         storage_partition: partition@3e800 {
-            label = "storage";
             reg = <0x0003e800 0x00001800>;
         };
     };
diff --git a/app/boards/arm/preonic/preonic_rev3.dts b/app/boards/arm/preonic/preonic_rev3.dts
index c19b1319..249c8f3c 100644
--- a/app/boards/arm/preonic/preonic_rev3.dts
+++ b/app/boards/arm/preonic/preonic_rev3.dts
@@ -23,7 +23,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
         row-gpios
             = <&gpioa 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
@@ -96,7 +95,6 @@
     status = "okay";
 cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -132,7 +130,6 @@ cdc_acm_uart: cdc_acm_uart {
 
         /* Set 6Kb of storage at the end of the 256Kb of flash */
         storage_partition: partition@3e800 {
-            label = "storage";
             reg = <0x0003e800 0x00001800>;
         };
     };
diff --git a/app/boards/arm/proton_c/proton_c.dts b/app/boards/arm/proton_c/proton_c.dts
index b5a490ee..3aad62c8 100644
--- a/app/boards/arm/proton_c/proton_c.dts
+++ b/app/boards/arm/proton_c/proton_c.dts
@@ -27,7 +27,6 @@
         compatible = "gpio-leds";
         led: led_0 {
             gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>;
-            label = "User LED";
         };
     };
 };
@@ -73,7 +72,6 @@
     status = "okay";
     cdc_acm_uart0: cdc_acm_uart0 {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -93,7 +91,6 @@
 
         /* Set 6Kb of storage at the end of the 256Kb of flash */
         storage_partition: partition@3e800 {
-            label = "storage";
             reg = <0x0003e800 0x00001800>;
         };
     };
diff --git a/app/boards/arm/puchi_ble/puchi_ble_v1.dts b/app/boards/arm/puchi_ble/puchi_ble_v1.dts
index b056f711..05aba8d3 100644
--- a/app/boards/arm/puchi_ble/puchi_ble_v1.dts
+++ b/app/boards/arm/puchi_ble/puchi_ble_v1.dts
@@ -25,19 +25,17 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
-    ext-power {
+    // Node name must match original "EXT_POWER" label to preserve user settings.
+    EXT_POWER {
         compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
         control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 2>;
         output-ohms = <2000000>;
         full-ohms = <(2000000 + 820000)>;
@@ -78,7 +76,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -94,11 +91,9 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "softdevice";
             reg = <0x00000000 0x00026000>;
         };
         code_partition: partition@26000 {
-            label = "code_partition";
             reg = <0x00026000 0x000c6000>;
         };
 
@@ -112,12 +107,10 @@
          * if enabled.
          */
         storage_partition: partition@ec000 {
-            label = "storage";
             reg = <0x000ec000 0x00008000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/arm/s40nc/s40nc.dts b/app/boards/arm/s40nc/s40nc.dts
index 6eb9e2a5..aff09460 100644
--- a/app/boards/arm/s40nc/s40nc.dts
+++ b/app/boards/arm/s40nc/s40nc.dts
@@ -37,7 +37,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -66,13 +65,11 @@
         compatible = "gpio-leds";
         blue_led: led_0 {
             gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
-            label = "Blue LED";
         };
     };
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 2>;
         output-ohms = <2000000>;
         full-ohms = <(2000000 + 820000)>;
@@ -99,7 +96,6 @@
     status = "okay";
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
@@ -114,12 +110,10 @@
         #size-cells = <1>;
 
         sd_partition: partition@0 {
-            label = "mbr";
             reg = <0x00000000 0x00001000>;
         };
 
         code_partition: partition@1000 {
-            label = "code_partition";
             reg = <0x00001000 0x000d3000>;
         };
 
@@ -133,12 +127,10 @@
          * if enabled.
          */
         storage_partition: partition@d4000 {
-            label = "storage";
             reg = <0x000d4000 0x00020000>;
         };
 
         boot_partition: partition@f4000 {
-            label = "adafruit_boot";
             reg = <0x000f4000 0x0000c000>;
         };
     };
diff --git a/app/boards/native_posix.overlay b/app/boards/native_posix.overlay
index f8a8f700..d5ebcf18 100644
--- a/app/boards/native_posix.overlay
+++ b/app/boards/native_posix.overlay
@@ -9,7 +9,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-mock";
-        label = "KSCAN_MOCK";
 
         rows = <2>;
         columns = <2>;
diff --git a/app/boards/native_posix_64.overlay b/app/boards/native_posix_64.overlay
index f8a8f700..d0526ca3 100644
--- a/app/boards/native_posix_64.overlay
+++ b/app/boards/native_posix_64.overlay
@@ -4,15 +4,24 @@
 
 / {
     chosen {
+        zephyr,console = &uart0;
         zmk,kscan = &kscan;
     };
 
     kscan: kscan {
         compatible = "zmk,kscan-mock";
-        label = "KSCAN_MOCK";
 
         rows = <2>;
         columns = <2>;
         exit-after;
     };
+
+    uart0: uart {
+        status = "okay";
+        compatible = "zephyr,native-posix-uart";
+        /* Dummy current-speed entry to comply with serial
+         * DTS binding
+         */
+        current-speed = <0>;
+    };
 };
diff --git a/app/boards/nrf52_bsim.conf b/app/boards/nrf52_bsim.conf
new file mode 100644
index 00000000..526f3bc7
--- /dev/null
+++ b/app/boards/nrf52_bsim.conf
@@ -0,0 +1,4 @@
+CONFIG_ZMK_BLE=y
+CONFIG_LOG=y
+CONFIG_LOG_BACKEND_SHOW_COLOR=n
+CONFIG_ZMK_LOG_LEVEL_DBG=y
diff --git a/app/boards/nrf52_bsim.overlay b/app/boards/nrf52_bsim.overlay
new file mode 100644
index 00000000..ec7c49ae
--- /dev/null
+++ b/app/boards/nrf52_bsim.overlay
@@ -0,0 +1,16 @@
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/kscan_mock.h>
+
+/ {
+    chosen {
+        zmk,kscan = &kscan;
+    };
+
+    kscan: kscan {
+        compatible = "zmk,kscan-mock";
+
+        rows = <2>;
+        columns = <2>;
+    };
+};
diff --git a/app/boards/seeeduino_xiao.overlay b/app/boards/seeeduino_xiao.overlay
index a2ddaea4..285ee4de 100644
--- a/app/boards/seeeduino_xiao.overlay
+++ b/app/boards/seeeduino_xiao.overlay
@@ -13,7 +13,6 @@
 &usb0 {
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
diff --git a/app/boards/seeeduino_xiao_ble.overlay b/app/boards/seeeduino_xiao_ble.overlay
index e6a5b62c..d2ffbe46 100644
--- a/app/boards/seeeduino_xiao_ble.overlay
+++ b/app/boards/seeeduino_xiao_ble.overlay
@@ -13,7 +13,6 @@
 
     vbatt: vbatt {
         compatible = "zmk,battery-voltage-divider";
-        label = "BATTERY";
         io-channels = <&adc 7>;
         power-gpios = <&gpio0 14 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>;
         output-ohms = <510000>;
@@ -28,7 +27,6 @@
 &usbd {
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
diff --git a/app/boards/shields/a_dux/a_dux.dtsi b/app/boards/shields/a_dux/a_dux.dtsi
index 28156f42..c13f3dd1 100644
--- a/app/boards/shields/a_dux/a_dux.dtsi
+++ b/app/boards/shields/a_dux/a_dux.dtsi
@@ -27,7 +27,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-direct";
-        label = "KSCAN";
         input-gpios =
             <&pro_micro  5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
             <&pro_micro  0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
diff --git a/app/boards/shields/bat43/bat43.overlay b/app/boards/shields/bat43/bat43.overlay
index fc906e0f..7ebe653a 100644
--- a/app/boards/shields/bat43/bat43.overlay
+++ b/app/boards/shields/bat43/bat43.overlay
@@ -28,7 +28,6 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5)         RC(6,0) RC(6,1) RC(6,2)
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/shields/bfo9000/bfo9000.dtsi b/app/boards/shields/bfo9000/bfo9000.dtsi
index c5547920..d9d09a83 100644
--- a/app/boards/shields/bfo9000/bfo9000.dtsi
+++ b/app/boards/shields/bfo9000/bfo9000.dtsi
@@ -28,7 +28,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
diff --git a/app/boards/shields/boardsource3x4/boardsource3x4.overlay b/app/boards/shields/boardsource3x4/boardsource3x4.overlay
index afbc9abf..389f5b7a 100644
--- a/app/boards/shields/boardsource3x4/boardsource3x4.overlay
+++ b/app/boards/shields/boardsource3x4/boardsource3x4.overlay
@@ -13,7 +13,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
          row-gpios
diff --git a/app/boards/shields/boardsource5x12/boardsource5x12.overlay b/app/boards/shields/boardsource5x12/boardsource5x12.overlay
index 080a2392..9a721d0c 100644
--- a/app/boards/shields/boardsource5x12/boardsource5x12.overlay
+++ b/app/boards/shields/boardsource5x12/boardsource5x12.overlay
@@ -13,7 +13,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         row-gpios
diff --git a/app/boards/shields/chalice/boards/nice_nano.overlay b/app/boards/shields/chalice/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/chalice/boards/nice_nano.overlay
+++ b/app/boards/shields/chalice/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/chalice/boards/nice_nano_v2.overlay b/app/boards/shields/chalice/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/chalice/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/chalice/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/chalice/chalice.overlay b/app/boards/shields/chalice/chalice.overlay
index 6778588b..85c9b1ed 100644
--- a/app/boards/shields/chalice/chalice.overlay
+++ b/app/boards/shields/chalice/chalice.overlay
@@ -44,7 +44,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/shields/clog/clog.dtsi b/app/boards/shields/clog/clog.dtsi
index 40e9a39f..bcc08c71 100644
--- a/app/boards/shields/clog/clog.dtsi
+++ b/app/boards/shields/clog/clog.dtsi
@@ -26,7 +26,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-direct";
-        label = "KSCAN";
 
         input-gpios
             = <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
diff --git a/app/boards/shields/clueboard_california/clueboard_california.overlay b/app/boards/shields/clueboard_california/clueboard_california.overlay
index dfa5d9cf..8cea791e 100644
--- a/app/boards/shields/clueboard_california/clueboard_california.overlay
+++ b/app/boards/shields/clueboard_california/clueboard_california.overlay
@@ -12,8 +12,6 @@
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-direct";
 
-        label = "KSCAN";
-
         input-gpios
             = <&gpioa 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
             , <&gpioa 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
diff --git a/app/boards/shields/contra/contra.overlay b/app/boards/shields/contra/contra.overlay
index 21e19425..0ac042d6 100644
--- a/app/boards/shields/contra/contra.overlay
+++ b/app/boards/shields/contra/contra.overlay
@@ -11,7 +11,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/shields/corne/boards/nice_nano.overlay b/app/boards/shields/corne/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/corne/boards/nice_nano.overlay
+++ b/app/boards/shields/corne/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/corne/boards/nice_nano_v2.overlay b/app/boards/shields/corne/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/corne/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/corne/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/corne/corne.dtsi b/app/boards/shields/corne/corne.dtsi
index 0e9eddf9..5058f67a 100644
--- a/app/boards/shields/corne/corne.dtsi
+++ b/app/boards/shields/corne/corne.dtsi
@@ -47,7 +47,6 @@ RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5)  RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -68,7 +67,6 @@ RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5)  RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/cradio/cradio.dtsi b/app/boards/shields/cradio/cradio.dtsi
index 57dcfd4b..3f7ed01c 100644
--- a/app/boards/shields/cradio/cradio.dtsi
+++ b/app/boards/shields/cradio/cradio.dtsi
@@ -27,7 +27,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-direct";
-        label = "KSCAN";
         input-gpios
         = <&pro_micro  7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
         , <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
diff --git a/app/boards/shields/cradio/cradio.keymap b/app/boards/shields/cradio/cradio.keymap
index 47bf0422..ab4591ba 100644
--- a/app/boards/shields/cradio/cradio.keymap
+++ b/app/boards/shields/cradio/cradio.keymap
@@ -12,7 +12,6 @@
 / {
     behaviors {
         ht: hold_tap {
-            label = "hold_tap";
             compatible = "zmk,behavior-hold-tap";
             #binding-cells = <2>;
             flavor = "tap-preferred";
diff --git a/app/boards/shields/crbn/crbn.overlay b/app/boards/shields/crbn/crbn.overlay
index 817a83d0..5cc9ec6c 100644
--- a/app/boards/shields/crbn/crbn.overlay
+++ b/app/boards/shields/crbn/crbn.overlay
@@ -13,7 +13,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
@@ -41,7 +40,6 @@
 
     encoder: encoder {
         compatible = "alps,ec11";
-        label = "ENCODER";
         a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         resolution = <2>;
diff --git a/app/boards/shields/eek/eek.overlay b/app/boards/shields/eek/eek.overlay
index f53c6b5b..8ec6714e 100644
--- a/app/boards/shields/eek/eek.overlay
+++ b/app/boards/shields/eek/eek.overlay
@@ -26,7 +26,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/shields/elephant42/boards/nice_nano.overlay b/app/boards/shields/elephant42/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/elephant42/boards/nice_nano.overlay
+++ b/app/boards/shields/elephant42/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/elephant42/boards/nice_nano_v2.overlay b/app/boards/shields/elephant42/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/elephant42/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/elephant42/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/elephant42/elephant42.dtsi b/app/boards/shields/elephant42/elephant42.dtsi
index b0e9a32e..d364bef9 100644
--- a/app/boards/shields/elephant42/elephant42.dtsi
+++ b/app/boards/shields/elephant42/elephant42.dtsi
@@ -26,7 +26,6 @@ RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5)                 RC(1,6) RC(1,7)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -45,7 +44,6 @@ RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5)                 RC(1,6) RC(1,7)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/ergodash/ergodash.dtsi b/app/boards/shields/ergodash/ergodash.dtsi
index d109fa66..7b9ac012 100644
--- a/app/boards/shields/ergodash/ergodash.dtsi
+++ b/app/boards/shields/ergodash/ergodash.dtsi
@@ -35,7 +35,6 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4)         RC(4,5) RC(4,6) RC(4,13) RC(4,12
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
 
diff --git a/app/boards/shields/eternal_keypad/boards/nice_nano.overlay b/app/boards/shields/eternal_keypad/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/eternal_keypad/boards/nice_nano.overlay
+++ b/app/boards/shields/eternal_keypad/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/eternal_keypad/boards/nice_nano_v2.overlay b/app/boards/shields/eternal_keypad/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/eternal_keypad/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/eternal_keypad/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/eternal_keypad/eternal_keypad.dtsi b/app/boards/shields/eternal_keypad/eternal_keypad.dtsi
index 6319d9e0..14e877e5 100644
--- a/app/boards/shields/eternal_keypad/eternal_keypad.dtsi
+++ b/app/boards/shields/eternal_keypad/eternal_keypad.dtsi
@@ -14,7 +14,6 @@
 
   kscan0: kscan {
     compatible = "zmk,kscan-gpio-matrix";
-    label = "KSCAN";
 
     diode-direction = "col2row";
 
diff --git a/app/boards/shields/fourier/fourier.dtsi b/app/boards/shields/fourier/fourier.dtsi
index 0902d687..fdd54901 100644
--- a/app/boards/shields/fourier/fourier.dtsi
+++ b/app/boards/shields/fourier/fourier.dtsi
@@ -30,7 +30,6 @@ RC(3,0)   RC(3,1) RC(3,2) RC(3,3) RC(3,4)            /**/  RC(3,6)        RC(3,9
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
diff --git a/app/boards/shields/helix/boards/nice_nano.overlay b/app/boards/shields/helix/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/helix/boards/nice_nano.overlay
+++ b/app/boards/shields/helix/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/helix/boards/nice_nano_v2.overlay b/app/boards/shields/helix/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/helix/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/helix/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/helix/helix.dtsi b/app/boards/shields/helix/helix.dtsi
index bbaec636..2ee68e0f 100644
--- a/app/boards/shields/helix/helix.dtsi
+++ b/app/boards/shields/helix/helix.dtsi
@@ -32,7 +32,6 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6)   RC(4,7) RC(4,8) RC(4,9
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
diff --git a/app/boards/shields/hummingbird/hummingbird.keymap b/app/boards/shields/hummingbird/hummingbird.keymap
index 990d7909..9f1a24c2 100644
--- a/app/boards/shields/hummingbird/hummingbird.keymap
+++ b/app/boards/shields/hummingbird/hummingbird.keymap
@@ -19,7 +19,6 @@
     behaviors {
         hm: homerow_mods {
             compatible = "zmk,behavior-hold-tap";
-            label = "homerow mods";
             #binding-cells = <2>;
             tapping_term_ms = <225>;
             flavor = "tap-preferred";
@@ -66,7 +65,7 @@
         };
 
         nav_layer {
-            label = "Nav";
+            display-name = "Nav";
             bindings = <
                 &trans     &trans     &trans      &trans          &trans       &trans           &kp HOME       &kp UARW &kp PG_UP  &trans
                 &trans     &trans     &trans      &trans          &trans       &trans           &kp LARW       &kp DARW &kp RARW   &trans
@@ -76,7 +75,7 @@
         };
 
         num_layer {
-            label = "Num";
+            display-name = "Num";
             bindings = <
                 &kp LBKT   &kp N7     &kp N8      &kp N9          &kp RBKT      &trans          &trans         &trans      &trans     &trans
                 &kp SEMI   &kp N4     &kp N5      &kp N6          &kp EQUAL     &trans          &trans         &trans      &trans     &trans
@@ -86,7 +85,7 @@
         };
 
         sym_layer {
-            label = "Sym";
+            display-name = "Sym";
             bindings = <
                 &kp LBRC   &kp LS(N7) &kp LS(N8)  &kp LS(N9)      &kp RBRC      &trans          &trans         &trans      &trans     &trans
                 &kp COLON  &kp LS(N4) &kp LS(N5)  &kp LS(N6)      &kp PLUS      &trans          &trans         &trans      &trans     &trans
diff --git a/app/boards/shields/hummingbird/hummingbird.overlay b/app/boards/shields/hummingbird/hummingbird.overlay
index 1b40acba..661e9489 100644
--- a/app/boards/shields/hummingbird/hummingbird.overlay
+++ b/app/boards/shields/hummingbird/hummingbird.overlay
@@ -29,7 +29,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "row2col";
 
         col-gpios
diff --git a/app/boards/shields/iris/iris.dtsi b/app/boards/shields/iris/iris.dtsi
index a0caf1ad..8c5bb447 100644
--- a/app/boards/shields/iris/iris.dtsi
+++ b/app/boards/shields/iris/iris.dtsi
@@ -32,7 +32,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,2) RC(4,9) RC(3,6) RC(3,7)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
diff --git a/app/boards/shields/jian/jian.dtsi b/app/boards/shields/jian/jian.dtsi
index 8e772791..1962ae15 100644
--- a/app/boards/shields/jian/jian.dtsi
+++ b/app/boards/shields/jian/jian.dtsi
@@ -62,7 +62,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
diff --git a/app/boards/shields/jiran/jiran.dtsi b/app/boards/shields/jiran/jiran.dtsi
index b7e74c27..55ba2cb0 100644
--- a/app/boards/shields/jiran/jiran.dtsi
+++ b/app/boards/shields/jiran/jiran.dtsi
@@ -67,7 +67,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
diff --git a/app/boards/shields/jorne/boards/nice_nano.overlay b/app/boards/shields/jorne/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/jorne/boards/nice_nano.overlay
+++ b/app/boards/shields/jorne/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/jorne/boards/nice_nano_v2.overlay b/app/boards/shields/jorne/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/jorne/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/jorne/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/jorne/jorne.dtsi b/app/boards/shields/jorne/jorne.dtsi
index 1d12b85c..e5300c86 100644
--- a/app/boards/shields/jorne/jorne.dtsi
+++ b/app/boards/shields/jorne/jorne.dtsi
@@ -63,7 +63,6 @@ RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5)  RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -84,7 +83,6 @@ RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5)  RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/knob_goblin/knob_goblin.overlay b/app/boards/shields/knob_goblin/knob_goblin.overlay
index 03051ce5..53372738 100644
--- a/app/boards/shields/knob_goblin/knob_goblin.overlay
+++ b/app/boards/shields/knob_goblin/knob_goblin.overlay
@@ -14,7 +14,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
          row-gpios
@@ -36,7 +35,6 @@
 
     top_encoder: encoder_top {
         compatible = "alps,ec11";
-        label = "TOP_ENCODER";
         a-gpios = <&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         steps = <80>;
@@ -45,7 +43,6 @@
 
     bottom_encoder: encoder_bottom {
         compatible = "alps,ec11";
-        label = "BOTTOM_ENCODER";
         a-gpios = <&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         steps = <80>;
@@ -66,7 +63,6 @@
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/kyria/boards/nice_nano.overlay b/app/boards/shields/kyria/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/kyria/boards/nice_nano.overlay
+++ b/app/boards/shields/kyria/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/kyria/boards/nice_nano_v2.overlay b/app/boards/shields/kyria/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/kyria/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/kyria/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/kyria/boards/nrfmicro_11.overlay b/app/boards/shields/kyria/boards/nrfmicro_11.overlay
index 8754dec6..dba8377e 100644
--- a/app/boards/shields/kyria/boards/nrfmicro_11.overlay
+++ b/app/boards/shields/kyria/boards/nrfmicro_11.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/kyria/boards/nrfmicro_11_flipped.overlay b/app/boards/shields/kyria/boards/nrfmicro_11_flipped.overlay
index 8754dec6..dba8377e 100644
--- a/app/boards/shields/kyria/boards/nrfmicro_11_flipped.overlay
+++ b/app/boards/shields/kyria/boards/nrfmicro_11_flipped.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/kyria/boards/nrfmicro_13.overlay b/app/boards/shields/kyria/boards/nrfmicro_13.overlay
index 8754dec6..dba8377e 100644
--- a/app/boards/shields/kyria/boards/nrfmicro_13.overlay
+++ b/app/boards/shields/kyria/boards/nrfmicro_13.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/kyria/kyria_common.dtsi b/app/boards/shields/kyria/kyria_common.dtsi
index 1056794d..f68b743e 100644
--- a/app/boards/shields/kyria/kyria_common.dtsi
+++ b/app/boards/shields/kyria/kyria_common.dtsi
@@ -15,21 +15,18 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
     };
 
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         steps = <80>;
         status = "disabled";
     };
 
     right_encoder: encoder_right {
         compatible = "alps,ec11";
-        label = "RIGHT_ENCODER";
         steps = <80>;
         status = "disabled";
     };
@@ -49,7 +46,6 @@
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <64>;
         segment-offset = <0>;
diff --git a/app/boards/shields/leeloo/boards/nice_nano_v2.overlay b/app/boards/shields/leeloo/boards/nice_nano_v2.overlay
index 5c451b73..e95fac9d 100644
--- a/app/boards/shields/leeloo/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/leeloo/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/leeloo/leeloo.keymap b/app/boards/shields/leeloo/leeloo.keymap
index bdbf8988..91e4f333 100644
--- a/app/boards/shields/leeloo/leeloo.keymap
+++ b/app/boards/shields/leeloo/leeloo.keymap
@@ -25,7 +25,7 @@
         compatible = "zmk,keymap";
 
         default_layer {
-            label = " QWERTY";
+            display-name = " QWERTY";
             bindings = <
 &kp ESC    &kp N1     &kp N2     &kp N3     &kp N4     &kp N5                           &kp N6     &kp N7     &kp N8     &kp N9     &kp N0     &kp BSLH
 &kp TAB    &kp Q      &kp W      &kp E      &kp R      &kp T                            &kp Y      &kp U      &kp I      &kp O      &kp P      &kp GRAV
@@ -38,7 +38,7 @@
         };
 
         lower_layer {
-            label = " Lower";
+            display-name = " Lower";
             bindings = <
 &trans     &kp F1     &kp F2     &kp F3     &kp F4     &kp F5                           &kp F6     &kp F7     &kp F8     &kp F9     &kp F10    &kp F11
 &trans     &trans     &trans     &trans     &trans     &trans                           &kp PG_UP  &kp HOME   &kp UP     &kp END    &trans     &kp F12
@@ -51,7 +51,7 @@
         };
 
         raise_layer {
-            label = " Raise";
+            display-name = " Raise";
             bindings = <
 &trans     &trans     &trans     &trans     &trans     &trans                           &bt BT_SEL 0  &bt BT_SEL 1  &bt BT_SEL 2  &bt BT_SEL 3  &bt BT_SEL 4  &trans
 &trans     &trans     &trans     &trans     &trans     &trans                           &trans        &trans        &trans        &trans        &sys_reset    &bootloader
diff --git a/app/boards/shields/leeloo/leeloo_common.dtsi b/app/boards/shields/leeloo/leeloo_common.dtsi
index ef775cfb..7c4ab22d 100644
--- a/app/boards/shields/leeloo/leeloo_common.dtsi
+++ b/app/boards/shields/leeloo/leeloo_common.dtsi
@@ -32,7 +32,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
 
@@ -47,7 +46,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
 
     left_encoder: left_encoder {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <120>;
@@ -56,7 +54,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
 
     right_encoder: right_encoder {
         compatible = "alps,ec11";
-        label = "RIGHT_ENCODER";
         a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <120>;
@@ -77,7 +74,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/leeloo/leeloo_rev2.keymap b/app/boards/shields/leeloo/leeloo_rev2.keymap
index a66205b6..a2eda050 100644
--- a/app/boards/shields/leeloo/leeloo_rev2.keymap
+++ b/app/boards/shields/leeloo/leeloo_rev2.keymap
@@ -37,7 +37,7 @@
         compatible = "zmk,keymap";
 
         default_layer {
-            label = " QWERTY";
+            display-name = " QWERTY";
             bindings = <
 &kp ESC    &kp N1     &kp N2     &kp N3     &kp N4     &kp N5                           &kp N6     &kp N7     &kp N8     &kp N9     &kp N0     &kp BSLH
 &kp TAB    &kp Q      &kp W      &kp E      &kp R      &kp T                            &kp Y      &kp U      &kp I      &kp O      &kp P      &kp GRAV
@@ -50,7 +50,7 @@
         };
 
         lower_layer {
-            label = " Lower";
+            display-name = " Lower";
             bindings = <
 &trans     &kp F1     &kp F2     &kp F3     &kp F4     &kp F5                           &kp F6     &kp F7     &kp F8     &kp F9     &kp F10    &kp F11
 &trans     &trans     &trans     &trans     &trans     &trans                           &kp PG_UP  &kp HOME   &kp UP     &kp END    &trans     &kp F12
@@ -63,7 +63,7 @@
         };
 
         raise_layer {
-            label = " Raise";
+            display-name = " Raise";
             bindings = <
 &trans     &trans     &trans     &trans     &trans     &trans                           &bt BT_SEL 0  &bt BT_SEL 1  &bt BT_SEL 2  &bt BT_SEL 3  &bt BT_SEL 4  &trans
 &trans     &trans     &trans     &trans     &trans     &trans                           &trans        &trans        &trans        &trans        &sys_reset    &bootloader
diff --git a/app/boards/shields/leeloo_micro/boards/nice_nano_v2.overlay b/app/boards/shields/leeloo_micro/boards/nice_nano_v2.overlay
index be5dc54e..ba29cb2c 100644
--- a/app/boards/shields/leeloo_micro/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/leeloo_micro/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.dtsi b/app/boards/shields/leeloo_micro/leeloo_micro.dtsi
index ab68a615..c07c5093 100644
--- a/app/boards/shields/leeloo_micro/leeloo_micro.dtsi
+++ b/app/boards/shields/leeloo_micro/leeloo_micro.dtsi
@@ -31,7 +31,6 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
 
@@ -45,7 +44,6 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7)
 
     left_encoder: left_encoder {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         status = "disabled";
@@ -54,7 +52,6 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7)
 
     right_encoder: right_encoder {
         compatible = "alps,ec11";
-        label = "RIGHT_ENCODER";
         a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         status = "disabled";
@@ -75,7 +72,6 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(3,4) RC(3,5) RC(2,5) RC(2,6) RC(2,7)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.keymap b/app/boards/shields/leeloo_micro/leeloo_micro.keymap
index 8526f5ac..2317015c 100644
--- a/app/boards/shields/leeloo_micro/leeloo_micro.keymap
+++ b/app/boards/shields/leeloo_micro/leeloo_micro.keymap
@@ -73,7 +73,7 @@
         compatible = "zmk,keymap";
 
         default_layer {
-            label = " QWERTY";
+            display-name = " QWERTY";
             bindings = <
 &kp Q      &kp W      &kp E      &kp R      &kp T                            &kp Y      &kp U      &kp I      &kp O      &kp P
 &kp A      &kp S      &kp D      &kp F      &kp G                            &kp H      &kp J      &kp K      &kp L      &kp SEMI
@@ -85,7 +85,7 @@
         };
 
         lower_layer {
-            label = " Lower";
+            display-name = " Lower";
             bindings = <
 &kp N1     &kp N2     &kp N3     &kp N4     &kp N5                           &kp N6     &kp N7     &kp N8     &kp N9     &kp N0
 &trans     &trans     &trans     &trans     &trans                           &trans     &trans     &trans     &trans     &kp QUOT
@@ -97,7 +97,7 @@
         };
 
         raise_layer {
-            label = " Raise";
+            display-name = " Raise";
             bindings = <
 &kp TAB    &trans     &trans     &trans     &trans                           &kp PG_UP  &kp HOME   &kp UP     &kp END    &kp BSLH
 &kp CAPS   &trans     &trans     &trans     &trans                           &kp PG_DN  &kp LEFT   &kp DOWN   &kp RIGHT  &kp GRAVE
@@ -109,7 +109,7 @@
         };
 
         adjust_layer {
-            label = " Adjust";
+            display-name = " Adjust";
             bindings = <
 
 &kp F1     &kp F2     &kp F3     &kp F4     &kp F5                           &trans     &trans     &trans     &trans     &trans
@@ -122,7 +122,7 @@
         };
 
         numpad_layer {
-            label = " NumPad";
+            display-name = " NumPad";
             bindings = <
 
 &trans     &none      &none      &none      &none                            &kp SLASH  &kp N7     &kp N8     &kp N9     &kp MINUS
@@ -135,7 +135,7 @@ RGBOFF     RGBEFF     RGBHUD     RGBSAD     RGBBRD     &trans     &trans     &no
         };
 
         ble_layer {
-            label = " BLE";
+            display-name = " BLE";
             bindings = <
 
 &bt BT0    &bt BT1    &bt BT2    &bt BT3    &bt BT4                          &bt BT0    &bt BT1    &bt BT2    &bt BT3    &bt BT4
diff --git a/app/boards/shields/lily58/boards/nice_nano.overlay b/app/boards/shields/lily58/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/lily58/boards/nice_nano.overlay
+++ b/app/boards/shields/lily58/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/lily58/boards/nice_nano_v2.overlay b/app/boards/shields/lily58/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/lily58/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/lily58/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/lily58/lily58.dtsi b/app/boards/shields/lily58/lily58.dtsi
index eb427a58..bd6d04e6 100644
--- a/app/boards/shields/lily58/lily58.dtsi
+++ b/app/boards/shields/lily58/lily58.dtsi
@@ -33,7 +33,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -48,7 +47,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
 
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -67,7 +65,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/lotus58/lotus58.dtsi b/app/boards/shields/lotus58/lotus58.dtsi
index 8b1c66f9..c58e9404 100644
--- a/app/boards/shields/lotus58/lotus58.dtsi
+++ b/app/boards/shields/lotus58/lotus58.dtsi
@@ -33,7 +33,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5)  RC(4,6)  RC(3,6) RC(3,7
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -47,7 +46,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5)  RC(4,6)  RC(3,6) RC(3,7
 
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -56,7 +54,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5)  RC(4,6)  RC(3,6) RC(3,7
 
     right_encoder: encoder_right {
         compatible = "alps,ec11";
-        label = "RIGHT_ENCODER";
         a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -76,7 +73,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5)  RC(4,6)  RC(3,6) RC(3,7
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/lotus58/lotus58.keymap b/app/boards/shields/lotus58/lotus58.keymap
index fae463c9..e9846e81 100644
--- a/app/boards/shields/lotus58/lotus58.keymap
+++ b/app/boards/shields/lotus58/lotus58.keymap
@@ -23,21 +23,18 @@
     behaviors {
         fofunc: four_ffour {
             compatible = "zmk,behavior-mod-morph";
-            label = "FOUR_FUNCFOUR";
             #binding-cells = <0>;
             bindings = <&kp N4>, <&kp F4>;
             mods = <(MOD_LALT|MOD_RALT)>;
         };
         sleft: s_left {
             compatible = "zmk,behavior-mod-morph";
-            label = "S_LEFT";
             #binding-cells = <0>;
             bindings = <&kp S>, <&kp LEFT>;
             mods = <(MOD_LGUI|MOD_RGUI)>;
         };
         fright: f_right {
             compatible = "zmk,behavior-mod-morph";
-            label = "R_RIGHT";
             #binding-cells = <0>;
             bindings = <&kp F>, <&kp RIGHT>;
             mods = <(MOD_LGUI|MOD_RGUI)>;
diff --git a/app/boards/shields/m60/m60.overlay b/app/boards/shields/m60/m60.overlay
index a2ab2593..7757abef 100644
--- a/app/boards/shields/m60/m60.overlay
+++ b/app/boards/shields/m60/m60.overlay
@@ -14,7 +14,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
diff --git a/app/boards/shields/microdox/boards/nice_nano.overlay b/app/boards/shields/microdox/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/microdox/boards/nice_nano.overlay
+++ b/app/boards/shields/microdox/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/microdox/boards/nice_nano_v2.overlay b/app/boards/shields/microdox/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/microdox/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/microdox/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/microdox/microdox.dtsi b/app/boards/shields/microdox/microdox.dtsi
index 57247e68..4869cfea 100644
--- a/app/boards/shields/microdox/microdox.dtsi
+++ b/app/boards/shields/microdox/microdox.dtsi
@@ -9,7 +9,6 @@
 / {
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
         row-gpios
             = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
diff --git a/app/boards/shields/microdox/microdox_common.dtsi b/app/boards/shields/microdox/microdox_common.dtsi
index 0460e012..1a762aae 100644
--- a/app/boards/shields/microdox/microdox_common.dtsi
+++ b/app/boards/shields/microdox/microdox_common.dtsi
@@ -38,7 +38,6 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4)  RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/microdox/microdox_v2.dtsi b/app/boards/shields/microdox/microdox_v2.dtsi
index 93fa4445..6eb7efa5 100644
--- a/app/boards/shields/microdox/microdox_v2.dtsi
+++ b/app/boards/shields/microdox/microdox_v2.dtsi
@@ -9,7 +9,6 @@
 / {
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
     };
 };
diff --git a/app/boards/shields/murphpad/boards/nice_nano.overlay b/app/boards/shields/murphpad/boards/nice_nano.overlay
index ac6c51d5..be8ff529 100644
--- a/app/boards/shields/murphpad/boards/nice_nano.overlay
+++ b/app/boards/shields/murphpad/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/murphpad/boards/nice_nano_v2.overlay b/app/boards/shields/murphpad/boards/nice_nano_v2.overlay
index ac6c51d5..be8ff529 100644
--- a/app/boards/shields/murphpad/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/murphpad/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/murphpad/murphpad.keymap b/app/boards/shields/murphpad/murphpad.keymap
index 74a852a8..069eeea3 100644
--- a/app/boards/shields/murphpad/murphpad.keymap
+++ b/app/boards/shields/murphpad/murphpad.keymap
@@ -56,7 +56,7 @@
         compatible = "zmk,keymap";
 
         default_layer {
-            label = "default layer";
+            display-name = "default layer";
             bindings = <
                 &bt BT_CLR       &kp TAB      &kp F5          &kp LC(LA(C))     &kp LG(D)
                 &rgb_ug RGB_TOG  &kp ESC      &kp KP_DIVIDE   &kp KP_MULTIPLY   &kp KP_MINUS
@@ -70,7 +70,7 @@
         };
 
         fn_layer {
-            label = "fn layer";
+            display-name = "fn layer";
             bindings = <
                 &trans      &trans     &trans        &trans          &trans
                 &trans      &kp KP_NUM &trans        &trans          &trans
diff --git a/app/boards/shields/murphpad/murphpad.overlay b/app/boards/shields/murphpad/murphpad.overlay
index f175c55e..f098ec8b 100644
--- a/app/boards/shields/murphpad/murphpad.overlay
+++ b/app/boards/shields/murphpad/murphpad.overlay
@@ -14,7 +14,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -36,7 +35,6 @@
 
     encoder_1: encoder_1 {
         compatible = "alps,ec11";
-        label = "Encoder 1";
         a-gpios = <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         steps = <80>;
@@ -45,7 +43,6 @@
 
     encoder_2: encoder_2 {
         compatible = "alps,ec11";
-        label = "Encoder 2";
         a-gpios = <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         steps = <80>;
@@ -60,7 +57,6 @@
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/naked60/naked60.overlay b/app/boards/shields/naked60/naked60.overlay
index 2260a4af..843c867f 100644
--- a/app/boards/shields/naked60/naked60.overlay
+++ b/app/boards/shields/naked60/naked60.overlay
@@ -11,7 +11,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/shields/nibble/boards/nice_nano.overlay b/app/boards/shields/nibble/boards/nice_nano.overlay
index 45c55263..3849a8fb 100644
--- a/app/boards/shields/nibble/boards/nice_nano.overlay
+++ b/app/boards/shields/nibble/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/nibble/boards/nice_nano_v2.overlay b/app/boards/shields/nibble/boards/nice_nano_v2.overlay
index 45c55263..3849a8fb 100644
--- a/app/boards/shields/nibble/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/nibble/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/nibble/nibble.keymap b/app/boards/shields/nibble/nibble.keymap
index 4cb6f5b0..8b25c5a4 100644
--- a/app/boards/shields/nibble/nibble.keymap
+++ b/app/boards/shields/nibble/nibble.keymap
@@ -19,7 +19,7 @@
         compatible = "zmk,keymap";
 
         default_layer {
-            label = "Default";
+            display-name = "Default";
 
             sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>;
 
@@ -32,7 +32,7 @@
             >;
         };
         function_layer {
-            label = "Function";
+            display-name = "Function";
 
             sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>;
 
diff --git a/app/boards/shields/nibble/nibble.overlay b/app/boards/shields/nibble/nibble.overlay
index 43be6c76..8b5a90da 100644
--- a/app/boards/shields/nibble/nibble.overlay
+++ b/app/boards/shields/nibble/nibble.overlay
@@ -15,7 +15,6 @@
 
     encoder_1: encoder_1 {
         compatible = "alps,ec11";
-        label = "Encoder 1";
         a-gpios = <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         steps = <80>;
@@ -24,7 +23,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-demux";
-        label = "KSCAN";
         polling-interval-msec = <25>;
         input-gpios
             = <&pro_micro 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
@@ -62,7 +60,6 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,3)                 RC(4,6)                 RC(4,9)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/nice_view/nice_view.overlay b/app/boards/shields/nice_view/nice_view.overlay
index 49ce0f23..e1965569 100644
--- a/app/boards/shields/nice_view/nice_view.overlay
+++ b/app/boards/shields/nice_view/nice_view.overlay
@@ -8,7 +8,6 @@
     status = "okay";
     nice_view: ls0xx@0 {
         compatible = "sharp,ls0xx";
-        label = "DISPLAY";
         spi-max-frequency = <1000000>;
         reg = <0>;
         width = <160>;
diff --git a/app/boards/shields/nice_view/widgets/status.c b/app/boards/shields/nice_view/widgets/status.c
index 453fd650..96b7d450 100644
--- a/app/boards/shields/nice_view/widgets/status.c
+++ b/app/boards/shields/nice_view/widgets/status.c
@@ -276,7 +276,7 @@ static void layer_status_update_cb(struct layer_status_state state) {
 
 static struct layer_status_state layer_status_get_state(const zmk_event_t *eh) {
     uint8_t index = zmk_keymap_highest_layer_active();
-    return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_label(index)};
+    return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_name(index)};
 }
 
 ZMK_DISPLAY_WIDGET_LISTENER(widget_layer_status, struct layer_status_state, layer_status_update_cb,
diff --git a/app/boards/shields/osprette/osprette.overlay b/app/boards/shields/osprette/osprette.overlay
index 546df783..e972e4da 100644
--- a/app/boards/shields/osprette/osprette.overlay
+++ b/app/boards/shields/osprette/osprette.overlay
@@ -26,7 +26,6 @@ RC(0,0) RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8)
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "row2col";
 
         col-gpios
diff --git a/app/boards/shields/pancake/pancake.overlay b/app/boards/shields/pancake/pancake.overlay
index 6fae463f..0ceb2d5c 100644
--- a/app/boards/shields/pancake/pancake.overlay
+++ b/app/boards/shields/pancake/pancake.overlay
@@ -11,7 +11,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/shields/qaz/qaz.keymap b/app/boards/shields/qaz/qaz.keymap
index e6794e7b..c887fb03 100644
--- a/app/boards/shields/qaz/qaz.keymap
+++ b/app/boards/shields/qaz/qaz.keymap
@@ -16,7 +16,6 @@
     behaviors {
         hm: homerow_mods {
             compatible = "zmk,behavior-hold-tap";
-            label = "homerow mods";
             #binding-cells = <2>;
             tapping-term-ms = <225>;
             flavor = "tap-preferred";
diff --git a/app/boards/shields/qaz/qaz.overlay b/app/boards/shields/qaz/qaz.overlay
index 76ee5ba7..814e5e1a 100644
--- a/app/boards/shields/qaz/qaz.overlay
+++ b/app/boards/shields/qaz/qaz.overlay
@@ -27,7 +27,6 @@
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/shields/quefrency/quefrency_left.overlay b/app/boards/shields/quefrency/quefrency_left.overlay
index a0f483ef..cf795841 100644
--- a/app/boards/shields/quefrency/quefrency_left.overlay
+++ b/app/boards/shields/quefrency/quefrency_left.overlay
@@ -12,7 +12,6 @@
      */
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
 
diff --git a/app/boards/shields/quefrency/quefrency_right.overlay b/app/boards/shields/quefrency/quefrency_right.overlay
index bf97d34b..446a614a 100644
--- a/app/boards/shields/quefrency/quefrency_right.overlay
+++ b/app/boards/shields/quefrency/quefrency_right.overlay
@@ -17,7 +17,6 @@
      */
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
 
diff --git a/app/boards/shields/redox/boards/nice_nano.overlay b/app/boards/shields/redox/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/redox/boards/nice_nano.overlay
+++ b/app/boards/shields/redox/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/redox/boards/nice_nano_v2.overlay b/app/boards/shields/redox/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/redox/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/redox/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/redox/redox.dtsi b/app/boards/shields/redox/redox.dtsi
index d2d72d0f..bf5ec9e8 100644
--- a/app/boards/shields/redox/redox.dtsi
+++ b/app/boards/shields/redox/redox.dtsi
@@ -32,7 +32,6 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,3)      RC(4,4)    RC(4,5) RC(4,6) RC(4,7) RC(4,8)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
diff --git a/app/boards/shields/reviung34/boards/nice_nano_v2.overlay b/app/boards/shields/reviung34/boards/nice_nano_v2.overlay
index b8d21398..d14b95db 100644
--- a/app/boards/shields/reviung34/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/reviung34/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/reviung34/reviung34.keymap b/app/boards/shields/reviung34/reviung34.keymap
index eefc510a..9a0d982d 100644
--- a/app/boards/shields/reviung34/reviung34.keymap
+++ b/app/boards/shields/reviung34/reviung34.keymap
@@ -25,7 +25,7 @@
         compatible = "zmk,keymap";
 
         base {
-            label = "Base";
+            display-name = "Base";
             bindings = <
 &kp Q       &kp W       &kp E      &kp R &kp T    &kp Y      &kp U       &kp I          &kp O         &kp P
 &kp A       &kp S       &kp D      &kp F &kp G    &kp H      &kp J       &kp K          &kp L         &kp SEMI
@@ -35,7 +35,7 @@
         };
 
         lower {
-            label = "Lower";
+            display-name = "Lower";
             bindings = <
 &kp EXCL &kp AT    &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS  &kp ASTRK &kp LPAR &kp RPAR
 &trans   &kp TILDE &kp DQT  &kp PIPE &trans    &trans    &kp UNDER &kp PLUS  &kp LBRC &kp RBRC
@@ -45,7 +45,7 @@
         };
 
         upper {
-            label = "Upper";
+            display-name = "Upper";
             bindings = <
 &kp N1 &kp N2    &kp N3  &kp N4   &kp N5 &kp N6 &kp N7    &kp N8    &kp N9   &kp N0
 &trans &kp GRAVE &kp SQT &kp BSLH &trans &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT
@@ -55,7 +55,7 @@
         };
 
         function {
-            label = "Function";
+            display-name = "Function";
             bindings = <
 &kp TAB &trans       &kp C_VOL_UP &trans       &trans    &trans &trans   &trans   &trans &kp ENTER
 &kp ESC &kp C_BRI_DN &kp C_VOL_DN &kp C_BRI_UP &trans    &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT
@@ -65,7 +65,7 @@
         };
 
         meta {
-            label = "Meta";
+            display-name = "Meta";
             bindings = <
 &rgb_ug RGB_HUI &rgb_ug RGB_SAI &rgb_ug RGB_BRI &rgb_ug RGB_SPI &rgb_ug RGB_EFF &none        &none        &none        &none        &none
 &rgb_ug RGB_HUD &rgb_ug RGB_SAD &rgb_ug RGB_BRD &rgb_ug RGB_SPD &rgb_ug RGB_EFR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4
diff --git a/app/boards/shields/reviung34/reviung34.overlay b/app/boards/shields/reviung34/reviung34.overlay
index 46d85996..6b1eb16f 100644
--- a/app/boards/shields/reviung34/reviung34.overlay
+++ b/app/boards/shields/reviung34/reviung34.overlay
@@ -38,7 +38,6 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(3,7)
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/shields/reviung41/boards/nice_nano.overlay b/app/boards/shields/reviung41/boards/nice_nano.overlay
index 8590149e..59180064 100644
--- a/app/boards/shields/reviung41/boards/nice_nano.overlay
+++ b/app/boards/shields/reviung41/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/reviung41/boards/nice_nano_v2.overlay b/app/boards/shields/reviung41/boards/nice_nano_v2.overlay
index 8590149e..59180064 100644
--- a/app/boards/shields/reviung41/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/reviung41/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/reviung41/reviung41.overlay b/app/boards/shields/reviung41/reviung41.overlay
index 55900cc9..0aecf619 100644
--- a/app/boards/shields/reviung41/reviung41.overlay
+++ b/app/boards/shields/reviung41/reviung41.overlay
@@ -27,7 +27,6 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(5,0) RC(5,1) RC(5,2) RC(5,3)
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/shields/reviung5/reviung5.keymap b/app/boards/shields/reviung5/reviung5.keymap
index 93669479..31c89cbc 100644
--- a/app/boards/shields/reviung5/reviung5.keymap
+++ b/app/boards/shields/reviung5/reviung5.keymap
@@ -17,7 +17,7 @@
             compatible = "zmk,keymap";
 
             base_layer {
-              label = "BASE";
+              display-name = "BASE";
               bindings = <
                 // ╭─────────────┬──────────────┬──────────────────┬─────────────┬─────────────╮
                      &mo BLE      &kp C_PREVIOUS  &kp C_PLAY_PAUSE    &kp C_NEXT   &kp C_MUTE
@@ -27,7 +27,7 @@
             };
 
             ble_layer {
-              label = "BLE";
+              display-name = "BLE";
               bindings = <
                 // ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮
                      &trans     &out OUT_TOG   &bt BT_PRV    &bt BT_NXT    &bt BT_CLR
diff --git a/app/boards/shields/reviung5/reviung5.overlay b/app/boards/shields/reviung5/reviung5.overlay
index 8b885245..b21a634a 100644
--- a/app/boards/shields/reviung5/reviung5.overlay
+++ b/app/boards/shields/reviung5/reviung5.overlay
@@ -22,7 +22,6 @@
 
     kscan0: kscan_0 {
             compatible = "zmk,kscan-gpio-matrix";
-            label = "KSCAN";
             diode-direction = "col2row";
 
             col-gpios
@@ -40,7 +39,6 @@
 
     encoder: encoder {
         compatible = "alps,ec11";
-        label = "encoder";
         a-gpios = <&pro_micro 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
diff --git a/app/boards/shields/reviung53/boards/nice_nano.overlay b/app/boards/shields/reviung53/boards/nice_nano.overlay
index 4df91903..24905ac2 100644
--- a/app/boards/shields/reviung53/boards/nice_nano.overlay
+++ b/app/boards/shields/reviung53/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/reviung53/boards/nice_nano_v2.overlay b/app/boards/shields/reviung53/boards/nice_nano_v2.overlay
index 4df91903..24905ac2 100644
--- a/app/boards/shields/reviung53/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/reviung53/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/reviung53/reviung53.overlay b/app/boards/shields/reviung53/reviung53.overlay
index 213b3b81..8c11c061 100644
--- a/app/boards/shields/reviung53/reviung53.overlay
+++ b/app/boards/shields/reviung53/reviung53.overlay
@@ -28,7 +28,6 @@ RC(6,0) RC(6,1) RC(6,2)      RC(6,3)         RC(6,4)                    RC(6,5)
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
diff --git a/app/boards/shields/romac/romac.overlay b/app/boards/shields/romac/romac.overlay
index 480d3f84..3d99e51b 100644
--- a/app/boards/shields/romac/romac.overlay
+++ b/app/boards/shields/romac/romac.overlay
@@ -13,7 +13,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
diff --git a/app/boards/shields/romac_plus/boards/nice_nano.overlay b/app/boards/shields/romac_plus/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/romac_plus/boards/nice_nano.overlay
+++ b/app/boards/shields/romac_plus/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/romac_plus/boards/nice_nano_v2.overlay b/app/boards/shields/romac_plus/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/romac_plus/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/romac_plus/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/romac_plus/romac_plus.dtsi b/app/boards/shields/romac_plus/romac_plus.dtsi
index 5324174b..12fd4387 100644
--- a/app/boards/shields/romac_plus/romac_plus.dtsi
+++ b/app/boards/shields/romac_plus/romac_plus.dtsi
@@ -27,7 +27,6 @@ RC(3,0) RC(3,1) RC(3,2)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -40,7 +39,6 @@ RC(3,0) RC(3,1) RC(3,2)
 
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
diff --git a/app/boards/shields/romac_plus/romac_plus.overlay b/app/boards/shields/romac_plus/romac_plus.overlay
index 2308e284..229b4a2c 100644
--- a/app/boards/shields/romac_plus/romac_plus.overlay
+++ b/app/boards/shields/romac_plus/romac_plus.overlay
@@ -13,7 +13,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
 
diff --git a/app/boards/shields/settings_reset/settings_reset.overlay b/app/boards/shields/settings_reset/settings_reset.overlay
index 48a5f223..1c3b7145 100644
--- a/app/boards/shields/settings_reset/settings_reset.overlay
+++ b/app/boards/shields/settings_reset/settings_reset.overlay
@@ -13,7 +13,6 @@
 
     kscan0: kscan {
         compatible = "zmk,kscan-mock";
-        label = "KSCAN";
         columns = <1>;
         rows = <0>;
 
diff --git a/app/boards/shields/snap/boards/nice_nano.overlay b/app/boards/shields/snap/boards/nice_nano.overlay
index 1a51eb16..924151c7 100644
--- a/app/boards/shields/snap/boards/nice_nano.overlay
+++ b/app/boards/shields/snap/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/snap/boards/nice_nano_v2.overlay b/app/boards/shields/snap/boards/nice_nano_v2.overlay
index 1a51eb16..924151c7 100644
--- a/app/boards/shields/snap/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/snap/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/snap/snap.dtsi b/app/boards/shields/snap/snap.dtsi
index 7523f35b..ef466723 100644
--- a/app/boards/shields/snap/snap.dtsi
+++ b/app/boards/shields/snap/snap.dtsi
@@ -15,14 +15,12 @@
 
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         steps = <80>;
         status = "disabled";
     };
 
     right_encoder: encoder_right {
         compatible = "alps,ec11";
-        label = "RIGHT_ENCODER";
         steps = <80>;
         status = "disabled";
     };
@@ -51,7 +49,6 @@ RC(5,7) RC(5,6) RC(5,5) RC(5,4)         RC(5,2)         RC(5,0)    RC(5,15)
 
     kscan_composite: kscan {
         compatible = "zmk,kscan-composite";
-        label = "KSCAN";
         rows = <6>;
         columns = <17>;
 
@@ -62,7 +59,6 @@ RC(5,7) RC(5,6) RC(5,5) RC(5,4)         RC(5,2)         RC(5,0)    RC(5,15)
 
     kscan_demux: kscan_demux {
         compatible = "zmk,kscan-gpio-demux";
-        label = "DEMUX";
         polling-interval-msec = <25>;
     };
 };
@@ -73,7 +69,6 @@ RC(5,7) RC(5,6) RC(5,5) RC(5,4)         RC(5,2)         RC(5,0)    RC(5,15)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/snap/snap.keymap b/app/boards/shields/snap/snap.keymap
index febaff97..8a95beda 100644
--- a/app/boards/shields/snap/snap.keymap
+++ b/app/boards/shields/snap/snap.keymap
@@ -20,7 +20,7 @@
         compatible = "zmk,keymap";
 
         default_layer {
-            label = "Default";
+            display-name = "Default";
             sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp C_VOL_UP C_VOL_DN>;
             bindings = <
              &kp ESC     &kp F1   &kp F2   &kp F3   &kp F4   &kp F5   &kp F6     &kp F7   &kp F8   &kp F9    &kp F10  &kp F11     &kp F12     &kp KP_NUM   &kp PAUSE_BREAK
@@ -33,7 +33,7 @@
         };
 
         function_layer {
-            label = "Function";
+            display-name = "Function";
             sensor-bindings = <&inc_dec_kp C_NEXT C_PREV &inc_dec_kp C_NEXT C_PREV>;
             bindings = <
              &bootloader &trans   &trans   &trans   &trans   &trans   &trans     &trans   &trans   &trans   &trans    &trans      &trans      &trans       &bootloader
diff --git a/app/boards/shields/snap/snap_right.overlay b/app/boards/shields/snap/snap_right.overlay
index ad04ae24..b303316a 100644
--- a/app/boards/shields/snap/snap_right.overlay
+++ b/app/boards/shields/snap/snap_right.overlay
@@ -9,7 +9,6 @@
 / {
 kscan_direct: kscan_direct {
     compatible = "zmk,kscan-gpio-direct";
-    label = "DIRECT";
     input-gpios
         = <&pro_micro 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
         ;
diff --git a/app/boards/shields/sofle/boards/nice_nano.overlay b/app/boards/shields/sofle/boards/nice_nano.overlay
index 336be4b0..f00f59f4 100644
--- a/app/boards/shields/sofle/boards/nice_nano.overlay
+++ b/app/boards/shields/sofle/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/sofle/boards/nice_nano_v2.overlay b/app/boards/shields/sofle/boards/nice_nano_v2.overlay
index 336be4b0..f00f59f4 100644
--- a/app/boards/shields/sofle/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/sofle/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/sofle/boards/nrfmicro_11.overlay b/app/boards/shields/sofle/boards/nrfmicro_11.overlay
index 336be4b0..f00f59f4 100644
--- a/app/boards/shields/sofle/boards/nrfmicro_11.overlay
+++ b/app/boards/shields/sofle/boards/nrfmicro_11.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/sofle/boards/nrfmicro_13.overlay b/app/boards/shields/sofle/boards/nrfmicro_13.overlay
index 336be4b0..f00f59f4 100644
--- a/app/boards/shields/sofle/boards/nrfmicro_13.overlay
+++ b/app/boards/shields/sofle/boards/nrfmicro_13.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/sofle/sofle.dtsi b/app/boards/shields/sofle/sofle.dtsi
index 4917ca32..c9bf5c8e 100644
--- a/app/boards/shields/sofle/sofle.dtsi
+++ b/app/boards/shields/sofle/sofle.dtsi
@@ -33,7 +33,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -47,7 +46,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
 
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -56,7 +54,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
 
     right_encoder: encoder_right {
         compatible = "alps,ec11";
-        label = "RIGHT_ENCODER";
         a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -76,7 +73,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/sofle/sofle.keymap b/app/boards/shields/sofle/sofle.keymap
index fbb0af7f..ed9f0f4f 100644
--- a/app/boards/shields/sofle/sofle.keymap
+++ b/app/boards/shields/sofle/sofle.keymap
@@ -30,7 +30,7 @@
         compatible = "zmk,keymap";
 
         default_layer {
-            label = "default";
+            display-name = "default";
 // ------------------------------------------------------------------------------------------------------------
 // |   `   |  1  |  2  |  3   |  4   |  5   |                   |  6   |  7    |  8    |  9   |   0   |       |
 // |  ESC  |  Q  |  W  |  E   |  R   |  T   |                   |  Y   |  U    |  I    |  O   |   P   | BKSPC |
@@ -49,7 +49,7 @@
         };
 
         lower_layer {
-            label = "lower";
+            display-name = "lower";
 // TODO: Some binds are waiting for shifted keycode support.
 // ------------------------------------------------------------------------------------------------------------
 // |       |  F1 |  F2 |  F3  |  F4  |  F5  |                   |  F6  |  F7   |  F8   |  F9  |  F10  |  F11  |
@@ -69,7 +69,7 @@
         };
 
         raise_layer {
-            label = "raise";
+            display-name = "raise";
 // ------------------------------------------------------------------------------------------------------------
 // | BTCLR | BT1  | BT2  |  BT3  |  BT4  |  BT5 |                |      |      |       |      |       |       |
 // |       | INS  | PSCR | GUI   |       |      |                | PGUP |      |   ^   |      |       |       |
@@ -94,7 +94,7 @@
 // |        | RGB_BRD | RGB_BRI |         |         |         |                  |      |      |       |      |       |       |
 // |        |         |         |         |         |         | RGB_TOG | |      |      |      |       |      |       |       |
 //                    |         |         |         |         |         | |      |      |      |       |      |
-            label = "adjust";
+            display-name = "adjust";
             bindings = <
 &bt BT_CLR        &bt BT_SEL 0    &bt BT_SEL 1    &bt BT_SEL 2    &bt BT_SEL 3    &bt BT_SEL 4                            &none &none &none &none &none &none
 &ext_power EP_TOG &rgb_ug RGB_HUD &rgb_ug RGB_HUI &rgb_ug RGB_SAD &rgb_ug RGB_SAI &rgb_ug RGB_EFF                         &none &none &none &none &none &none
diff --git a/app/boards/shields/splitkb_aurora_corne/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_corne/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/splitkb_aurora_corne/boards/nice_nano.overlay
+++ b/app/boards/shields/splitkb_aurora_corne/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/splitkb_aurora_corne/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_corne/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/splitkb_aurora_corne/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/splitkb_aurora_corne/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi
index 3eefdc6a..7911f151 100644
--- a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi
+++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi
@@ -47,7 +47,6 @@ RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5)  RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10
 
     left_encoder: left_encoder {
         compatible = "alps,ec11";
-        label = "L_ENCODER";
         steps = <80>;
         status = "disabled";
 
@@ -57,7 +56,6 @@ RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5)  RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10
 
     right_encoder: right_encoder {
         compatible = "alps,ec11";
-        label = "R_ENCODER";
         steps = <80>;
         status = "disabled";
 
@@ -78,7 +76,6 @@ RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5)  RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_left.overlay b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_left.overlay
index 89563f42..df930cd2 100644
--- a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_left.overlay
+++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_left.overlay
@@ -13,8 +13,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-
-        label = "KSCAN";
         diode-direction = "col2row";
 
         row-gpios
diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_right.overlay b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_right.overlay
index e05df223..3823cdfb 100644
--- a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_right.overlay
+++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne_right.overlay
@@ -13,8 +13,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-
-        label = "KSCAN";
         diode-direction = "col2row";
 
         row-gpios
diff --git a/app/boards/shields/splitkb_aurora_helix/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano.overlay
index 8f1629ce..8228d530 100644
--- a/app/boards/shields/splitkb_aurora_helix/boards/nice_nano.overlay
+++ b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/splitkb_aurora_helix/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano_v2.overlay
index 8f1629ce..8228d530 100644
--- a/app/boards/shields/splitkb_aurora_helix/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/splitkb_aurora_helix/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.dtsi b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.dtsi
index e580e87d..29b6ddde 100644
--- a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.dtsi
+++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix.dtsi
@@ -33,7 +33,6 @@
 
     left_encoder: left_encoder {
         compatible = "alps,ec11";
-        label = "L_ENCODER";
         steps = <144>;
         status = "disabled";
 
@@ -43,7 +42,6 @@
 
     right_encoder: right_encoder {
         compatible = "alps,ec11";
-        label = "R_ENCODER";
         steps = <144>;
         status = "disabled";
 
@@ -64,7 +62,6 @@
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_left.overlay b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_left.overlay
index c9830658..59d82553 100644
--- a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_left.overlay
+++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_left.overlay
@@ -13,8 +13,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-
-        label = "KSCAN";
         diode-direction = "col2row";
 
         row-gpios
diff --git a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_right.overlay b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_right.overlay
index 48572de9..95cea9ec 100644
--- a/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_right.overlay
+++ b/app/boards/shields/splitkb_aurora_helix/splitkb_aurora_helix_right.overlay
@@ -13,8 +13,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-
-        label = "KSCAN";
         diode-direction = "col2row";
 
         row-gpios
diff --git a/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano.overlay
index 0eafa704..fa6ac6dc 100644
--- a/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano.overlay
+++ b/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano.overlay
@@ -26,7 +26,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano_v2.overlay
index 6601d27d..08452266 100644
--- a/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/splitkb_aurora_lily58/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.dtsi b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.dtsi
index 06b3ef39..fb993dbb 100644
--- a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.dtsi
+++ b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58.dtsi
@@ -33,7 +33,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,1) RC(4,10) RC(3,6) RC(3,7)
 
     left_encoder: left_encoder {
         compatible = "alps,ec11";
-        label = "L_ENCODER";
         steps = <80>;
         status = "disabled";
 
@@ -43,7 +42,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,1) RC(4,10) RC(3,6) RC(3,7)
 
     right_encoder: right_encoder {
         compatible = "alps,ec11";
-        label = "R_ENCODER";
         steps = <80>;
         status = "disabled";
 
@@ -64,7 +62,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,1) RC(4,10) RC(3,6) RC(3,7)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_left.overlay b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_left.overlay
index c4f12dda..fc38bbcb 100644
--- a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_left.overlay
+++ b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_left.overlay
@@ -13,8 +13,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-
-        label = "KSCAN";
         diode-direction = "row2col";
 
         row-gpios
diff --git a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_right.overlay b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_right.overlay
index 09da298c..c9a96491 100644
--- a/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_right.overlay
+++ b/app/boards/shields/splitkb_aurora_lily58/splitkb_aurora_lily58_right.overlay
@@ -13,8 +13,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-
-        label = "KSCAN";
         diode-direction = "row2col";
 
         row-gpios
diff --git a/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano.overlay
index 8f1629ce..8228d530 100644
--- a/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano.overlay
+++ b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano_v2.overlay
index 8f1629ce..8228d530 100644
--- a/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/splitkb_aurora_sofle/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi
index 798cd84e..c064456a 100644
--- a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi
+++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi
@@ -33,7 +33,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
 
     left_encoder: left_encoder {
         compatible = "alps,ec11";
-        label = "L_ENCODER";
         steps = <144>;
         status = "disabled";
 
@@ -43,7 +42,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
 
     right_encoder: right_encoder {
         compatible = "alps,ec11";
-        label = "R_ENCODER";
         steps = <144>;
         status = "disabled";
 
@@ -64,7 +62,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,5) RC(4,6) RC(3,6) RC(3,7)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_left.overlay b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_left.overlay
index 1adaf401..024c9e75 100644
--- a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_left.overlay
+++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_left.overlay
@@ -13,8 +13,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-
-        label = "KSCAN";
         diode-direction = "col2row";
 
         row-gpios
diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_right.overlay b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_right.overlay
index 3249b941..58df0026 100644
--- a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_right.overlay
+++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle_right.overlay
@@ -13,8 +13,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-
-        label = "KSCAN";
         diode-direction = "col2row";
 
         row-gpios
diff --git a/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano.overlay b/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano.overlay
+++ b/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano_v2.overlay b/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano_v2.overlay
index 810340f9..424a617b 100644
--- a/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/splitkb_aurora_sweep/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi
index c5483af5..404782c7 100644
--- a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi
+++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi
@@ -27,28 +27,24 @@
 
     left_encoder1: left_encoder1 {
         compatible = "alps,ec11";
-        label = "L_ENCODER1";
         steps = <80>;
         status = "disabled";
     };
 
     left_encoder2: left_encoder2 {
         compatible = "alps,ec11";
-        label = "L_ENCODER2";
         steps = <80>;
         status = "disabled";
     };
 
     right_encoder1: right_encoder1 {
         compatible = "alps,ec11";
-        label = "R_ENCODER1";
         steps = <80>;
         status = "disabled";
     };
 
     right_encoder2: right_encoder2 {
         compatible = "alps,ec11";
-        label = "R_ENCODER2";
         steps = <80>;
         status = "disabled";
     };
@@ -66,7 +62,6 @@
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_left.overlay b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_left.overlay
index f62d24fa..4a1bec90 100644
--- a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_left.overlay
+++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_left.overlay
@@ -13,8 +13,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-
-        label = "KSCAN";
         diode-direction = "row2col";
 
         row-gpios
diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_right.overlay b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_right.overlay
index ff1d16d3..c3655477 100644
--- a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_right.overlay
+++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep_right.overlay
@@ -13,8 +13,6 @@
 
     kscan: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-
-        label = "KSCAN";
         diode-direction = "row2col";
 
         row-gpios
diff --git a/app/boards/shields/splitreus62/splitreus62.dtsi b/app/boards/shields/splitreus62/splitreus62.dtsi
index abc3b7f7..4a1a58a5 100644
--- a/app/boards/shields/splitreus62/splitreus62.dtsi
+++ b/app/boards/shields/splitreus62/splitreus62.dtsi
@@ -34,7 +34,6 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5)                 RC(4,6) RC(4,7)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "row2col";
         row-gpios
diff --git a/app/boards/shields/tg4x/boards/nice_nano.overlay b/app/boards/shields/tg4x/boards/nice_nano.overlay
index 85ab6fbc..84441899 100644
--- a/app/boards/shields/tg4x/boards/nice_nano.overlay
+++ b/app/boards/shields/tg4x/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/tg4x/boards/nice_nano_v2.overlay b/app/boards/shields/tg4x/boards/nice_nano_v2.overlay
index 85ab6fbc..84441899 100644
--- a/app/boards/shields/tg4x/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/tg4x/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/tg4x/tg4x.keymap b/app/boards/shields/tg4x/tg4x.keymap
index 89a478ae..5c71ae5c 100644
--- a/app/boards/shields/tg4x/tg4x.keymap
+++ b/app/boards/shields/tg4x/tg4x.keymap
@@ -12,7 +12,6 @@
     behaviors {
         ht: hold_tap {
             compatible = "zmk,behavior-hold-tap";
-            label = "Hold Tap";
             #binding-cells = <2>;
             tapping-term-ms = <200>;
             flavor = "tap-preferred";
diff --git a/app/boards/shields/tg4x/tg4x.overlay b/app/boards/shields/tg4x/tg4x.overlay
index c0b1b3bc..e53275c6 100644
--- a/app/boards/shields/tg4x/tg4x.overlay
+++ b/app/boards/shields/tg4x/tg4x.overlay
@@ -9,7 +9,6 @@
 / {
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
 
diff --git a/app/boards/shields/tidbit/boards/nice_nano.overlay b/app/boards/shields/tidbit/boards/nice_nano.overlay
index 75514ac4..b0895433 100644
--- a/app/boards/shields/tidbit/boards/nice_nano.overlay
+++ b/app/boards/shields/tidbit/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/tidbit/boards/nice_nano_v2.overlay b/app/boards/shields/tidbit/boards/nice_nano_v2.overlay
index 75514ac4..b0895433 100644
--- a/app/boards/shields/tidbit/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/tidbit/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/tidbit/tidbit.dtsi b/app/boards/shields/tidbit/tidbit.dtsi
index c7af2001..110c3fc8 100644
--- a/app/boards/shields/tidbit/tidbit.dtsi
+++ b/app/boards/shields/tidbit/tidbit.dtsi
@@ -9,7 +9,6 @@
 / {
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "row2col";
 
@@ -46,7 +45,6 @@
 
     encoder_1_top_row: encoder_1_top_row {
         compatible = "alps,ec11";
-        label = "Top Row Encoder";
         a-gpios = <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         steps = <80>;
@@ -55,7 +53,6 @@
 
     encoder_1: encoder_1 {
         compatible = "alps,ec11";
-        label = "Encoder 1";
         a-gpios = <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         steps = <80>;
@@ -64,7 +61,6 @@
 
     encoder_2: encoder_2 {
         compatible = "alps,ec11";
-        label = "Encoder 2";
         a-gpios = <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         steps = <80>;
@@ -73,7 +69,6 @@
 
     encoder_3: encoder_3 {
         compatible = "alps,ec11";
-        label = "Encoder 3";
         a-gpios = <&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         steps = <80>;
@@ -82,7 +77,6 @@
 
     encoder_4: encoder_4 {
         compatible = "alps,ec11";
-        label = "Encoder 4";
         a-gpios = <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
         steps = <80>;
@@ -102,7 +96,6 @@
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <32>;
         segment-offset = <0>;
diff --git a/app/boards/shields/two_percent_milk/boards/nice_nano.overlay b/app/boards/shields/two_percent_milk/boards/nice_nano.overlay
index 75514ac4..b0895433 100644
--- a/app/boards/shields/two_percent_milk/boards/nice_nano.overlay
+++ b/app/boards/shields/two_percent_milk/boards/nice_nano.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/two_percent_milk/boards/nice_nano_v2.overlay b/app/boards/shields/two_percent_milk/boards/nice_nano_v2.overlay
index 75514ac4..b0895433 100644
--- a/app/boards/shields/two_percent_milk/boards/nice_nano_v2.overlay
+++ b/app/boards/shields/two_percent_milk/boards/nice_nano_v2.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/two_percent_milk/boards/nrfmicro_11.overlay b/app/boards/shields/two_percent_milk/boards/nrfmicro_11.overlay
index d20e58e7..26079169 100644
--- a/app/boards/shields/two_percent_milk/boards/nrfmicro_11.overlay
+++ b/app/boards/shields/two_percent_milk/boards/nrfmicro_11.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/two_percent_milk/boards/nrfmicro_11_flipped.overlay b/app/boards/shields/two_percent_milk/boards/nrfmicro_11_flipped.overlay
index 31678980..e1218ffd 100644
--- a/app/boards/shields/two_percent_milk/boards/nrfmicro_11_flipped.overlay
+++ b/app/boards/shields/two_percent_milk/boards/nrfmicro_11_flipped.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/two_percent_milk/boards/nrfmicro_13.overlay b/app/boards/shields/two_percent_milk/boards/nrfmicro_13.overlay
index d20e58e7..26079169 100644
--- a/app/boards/shields/two_percent_milk/boards/nrfmicro_13.overlay
+++ b/app/boards/shields/two_percent_milk/boards/nrfmicro_13.overlay
@@ -25,7 +25,6 @@
 
     led_strip: ws2812@0 {
         compatible = "worldsemi,ws2812-spi";
-        label = "WS2812";
 
         /* SPI */
         reg = <0>; /* ignored, but necessary for SPI bindings */
diff --git a/app/boards/shields/two_percent_milk/two_percent_milk.overlay b/app/boards/shields/two_percent_milk/two_percent_milk.overlay
index 8d4a244a..474150ef 100644
--- a/app/boards/shields/two_percent_milk/two_percent_milk.overlay
+++ b/app/boards/shields/two_percent_milk/two_percent_milk.overlay
@@ -12,8 +12,6 @@
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-direct";
 
-        label = "KSCAN";
-
         input-gpios
             = <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
             , <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
diff --git a/app/boards/shields/waterfowl/waterfowl.dtsi b/app/boards/shields/waterfowl/waterfowl.dtsi
index 3d914094..bbe60acd 100644
--- a/app/boards/shields/waterfowl/waterfowl.dtsi
+++ b/app/boards/shields/waterfowl/waterfowl.dtsi
@@ -31,7 +31,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4)                                 RC(3,5)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -44,7 +43,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4)                                 RC(3,5)
 
     roller_left_encoder: encoder_left_roller {
         compatible = "alps,ec11";
-        label = "ROLLER_LEFT_ENCODER";
         a-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -53,7 +51,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4)                                 RC(3,5)
 
     dial_left_encoder: encoder_left_dial {
         compatible = "alps,ec11";
-        label = "DIAL_LEFT_ENCODER";
         a-gpios = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -62,7 +59,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4)                                 RC(3,5)
 
     roller_right_encoder: encoder_right_roller {
         compatible = "alps,ec11";
-        label = "ROLLER_RIGHT_ENCODER";
         a-gpios = <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -71,7 +67,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4)                                 RC(3,5)
 
     dial_right_encoder: encoder_right_dial {
         compatible = "alps,ec11";
-        label = "DIAL_RIGHT_ENCODER";
         a-gpios = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -98,7 +93,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4)                                 RC(3,5)
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <64>;
         segment-offset = <0>;
diff --git a/app/boards/shields/zmk_uno/Kconfig.defconfig b/app/boards/shields/zmk_uno/Kconfig.defconfig
index 11c63a5a..cccca1d2 100644
--- a/app/boards/shields/zmk_uno/Kconfig.defconfig
+++ b/app/boards/shields/zmk_uno/Kconfig.defconfig
@@ -1,7 +1,7 @@
 # Copyright (c) 2022 The ZMK Contributors
 # SPDX-License-Identifier: MIT
 
-if SHIELD_ZMK_UNO
+if SHIELD_ZMK_UNO_BASE
 
 config ZMK_KEYBOARD_NAME
     default "ZMK Uno"
diff --git a/app/boards/shields/zmk_uno/Kconfig.shield b/app/boards/shields/zmk_uno/Kconfig.shield
index 958915f5..0b0b3d73 100644
--- a/app/boards/shields/zmk_uno/Kconfig.shield
+++ b/app/boards/shields/zmk_uno/Kconfig.shield
@@ -1,5 +1,20 @@
 # Copyright (c) 2022 The ZMK Contributors
 # SPDX-License-Identifier: MIT
 
+config SHIELD_ZMK_UNO_BASE
+    bool
+
 config SHIELD_ZMK_UNO
     def_bool $(shields_list_contains,zmk_uno)
+    select SHIELD_ZMK_UNO_BASE
+
+config SHIELD_ZMK_UNO_SPLIT_LEFT
+    def_bool $(shields_list_contains,zmk_uno_split_left)
+    select SHIELD_ZMK_UNO_BASE
+    select ZMK_SPLIT
+    select ZMK_SPLIT_ROLE_CENTRAL
+
+config SHIELD_ZMK_UNO_SPLIT_RIGHT
+    def_bool $(shields_list_contains,zmk_uno_split_right)
+    select SHIELD_ZMK_UNO_BASE
+    select ZMK_SPLIT
\ No newline at end of file
diff --git a/app/boards/shields/zmk_uno/zmk_uno.conf b/app/boards/shields/zmk_uno/zmk_uno.conf
index cf282bac..0c46ea98 100644
--- a/app/boards/shields/zmk_uno/zmk_uno.conf
+++ b/app/boards/shields/zmk_uno/zmk_uno.conf
@@ -4,6 +4,8 @@
 CONFIG_LOG=y
 CONFIG_ZMK_LOG_LEVEL_DBG=y
 
+CONFIG_ZMK_BLE_PASSKEY_ENTRY=n
+
 # Uncomment for Single color backlight
 # CONFIG_ZMK_BACKLIGHT=y
 
diff --git a/app/boards/shields/zmk_uno/zmk_uno.dtsi b/app/boards/shields/zmk_uno/zmk_uno.dtsi
new file mode 100644
index 00000000..63deb06a
--- /dev/null
+++ b/app/boards/shields/zmk_uno/zmk_uno.dtsi
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2022 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <dt-bindings/led/led.h>
+#include <dt-bindings/zmk/matrix_transform.h>
+
+&arduino_i2c {
+    status = "okay";
+};
+
+nice_view_spi: &arduino_spi {
+    status = "okay";
+
+    cs-gpios = <&arduino_header 16 GPIO_ACTIVE_HIGH>;
+
+    // Needed so the nice_view shield will enhance the existing node which falls *first*
+    // on the bus, properly picking up the first `cs-gpios` specifier.
+    ls0xx@0 {
+        reg = <0>;
+    };
+
+    led_strip: ws2812@0 {
+        compatible = "worldsemi,ws2812-spi";
+
+        /* SPI */
+        reg = <0>; /* ignored, but necessary for SPI bindings */
+        spi-max-frequency = <4000000>;
+
+        /* WS2812 */
+        chain-length = <7>; /* 4 underglow + 3 per-key LEDs */
+        spi-one-frame = <0x70>;
+        spi-zero-frame = <0x40>;
+
+        color-mapping = <LED_COLOR_ID_GREEN LED_COLOR_ID_RED LED_COLOR_ID_BLUE>;
+    };
+};
+
+/ {
+    chosen {
+        zmk,kscan = &kscan_matrix_comp;
+        zmk,backlight = &backlight;
+        zmk,underglow = &led_strip;
+        zmk,matrix-transform = &matrix_transform;
+    };
+
+    // Commented out until we add more powerful power domain support
+    // external_power {
+        //  compatible = "zmk,ext-power-generic";
+        //  init-delay-ms = <200>;
+        //  control-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>;
+    // };
+
+    rgb_power {
+        compatible = "zmk,ext-power-generic";
+        init-delay-ms = <200>;
+        control-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>;
+    };
+
+    backlight: gpioleds {
+        compatible = "gpio-leds";
+        gpio_led_0 {
+            gpios = <&arduino_header 12 GPIO_ACTIVE_HIGH>;
+        };
+    };
+
+    matrix_transform: matrix_transform {
+        compatible = "zmk,matrix-transform";
+        rows = <3>;
+        columns = <4>;
+
+        map = <
+        RC(0,0) RC(0,1)
+        RC(1,0) RC(1,1)
+        RC(2,0) RC(2,1) RC(2,2)
+        >;
+    };
+
+    direct_matrix_transform: direct_matrix_transform {
+        compatible = "zmk,matrix-transform";
+        rows = <3>;
+        columns = <4>;
+
+        map = <
+        RC(0,0) RC(0,1)
+        RC(0,2) RC(0,3)
+        RC(1,0) RC(1,1) RC(1,2)
+        >;
+    };
+
+
+    kscan_matrix_comp: kscan_matrix_comp {
+        compatible = "zmk,kscan-composite";
+        rows = <1>;
+        columns = <7>;
+
+        matrix {
+            kscan = <&kscan_matrix>;
+        };
+
+        toggle {
+            kscan = <&kscan_sp3t_toggle>;
+            row-offset = <2>;
+        };
+
+    };
+
+    kscan_direct_comp: kscan_direct_comp {
+        compatible = "zmk,kscan-composite";
+        status = "disabled";
+
+        matrix {
+            kscan = <&kscan_direct>;
+        };
+
+        toggle {
+            kscan = <&kscan_sp3t_toggle>;
+            row-offset = <1>;
+        };
+
+    };
+
+    kscan_matrix: kscan_matrix {
+        compatible = "zmk,kscan-gpio-matrix";
+
+        diode-direction = "col2row";
+
+        col-gpios
+        = <&arduino_header 10 GPIO_ACTIVE_HIGH>
+        , <&arduino_header 9  GPIO_ACTIVE_HIGH>
+        ;
+
+        row-gpios
+        = <&arduino_header 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+        , <&arduino_header 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+        ;
+
+    };
+
+    kscan_direct: kscan_direct {
+        compatible = "zmk,kscan-gpio-direct";
+        status = "disabled";
+
+        input-gpios
+        = <&arduino_header 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
+        , <&arduino_header 9  (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
+        , <&arduino_header 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
+        , <&arduino_header 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
+        ;
+
+    };
+
+    kscan_sp3t_toggle: kscan_sp3t_toggle {
+        compatible = "zmk,kscan-gpio-direct";
+        toggle-mode;
+
+        input-gpios
+        = <&arduino_header 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
+        , <&arduino_header 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
+        , <&arduino_header 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
+        ;
+    };
+
+    encoder: encoder {
+        steps = <80>;
+        compatible = "alps,ec11";
+        a-gpios = <&arduino_header 15 GPIO_PULL_UP>;
+        b-gpios = <&arduino_header 14 GPIO_PULL_UP>;
+    };
+};
diff --git a/app/boards/shields/zmk_uno/zmk_uno.overlay b/app/boards/shields/zmk_uno/zmk_uno.overlay
index 02bb4ad8..07181280 100644
--- a/app/boards/shields/zmk_uno/zmk_uno.overlay
+++ b/app/boards/shields/zmk_uno/zmk_uno.overlay
@@ -4,180 +4,12 @@
  * SPDX-License-Identifier: MIT
  */
 
-#include <dt-bindings/led/led.h>
-#include <dt-bindings/zmk/matrix_transform.h>
-
-&arduino_i2c {
-    status = "okay";
-};
-
-nice_view_spi: &arduino_spi {
-    status = "okay";
-
-    cs-gpios = <&arduino_header 16 GPIO_ACTIVE_HIGH>;
-
-    // Needed so the nice_view shield will enhance the existing node which falls *first*
-    // on the bus, properly picking up the first `cs-gpios` specifier.
-    ls0xx@0 {
-        reg = <0>;
-    };
-
-    led_strip: ws2812@0 {
-        compatible = "worldsemi,ws2812-spi";
-
-        /* SPI */
-        reg = <0>; /* ignored, but necessary for SPI bindings */
-        spi-max-frequency = <4000000>;
-
-        /* WS2812 */
-        chain-length = <7>; /* 4 underglow + 3 per-key LEDs */
-        spi-one-frame = <0x70>;
-        spi-zero-frame = <0x40>;
-
-        color-mapping = <LED_COLOR_ID_GREEN LED_COLOR_ID_RED LED_COLOR_ID_BLUE>;
-    };
-};
+ #include "zmk_uno.dtsi"
 
 / {
     chosen {
-        zmk,kscan = &kscan_matrix_comp;
-        zmk,backlight = &backlight;
-        zmk,underglow = &led_strip;
         zmk,matrix-transform = &matrix_transform;
     };
-
-    // Commented out until we add more powerful power domain support
-    // external_power {
-        //  compatible = "zmk,ext-power-generic";
-        //  label = "EXT_POWER";
-        //  init-delay-ms = <200>;
-        //  control-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>;
-    // };
-
-    rgb_power {
-        compatible = "zmk,ext-power-generic";
-        label = "EXT_POWER";
-        // label = "RGB_POWER";
-        init-delay-ms = <200>;
-        control-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>;
-    };
-
-    backlight: gpioleds {
-        compatible = "gpio-leds";
-        label = "Backlight LEDs";
-        gpio_led_0 {
-            gpios = <&arduino_header 12 GPIO_ACTIVE_HIGH>;
-            label = "Backlight LED 0";
-        };
-    };
-
-    matrix_transform: matrix_transform {
-        compatible = "zmk,matrix-transform";
-        rows = <3>;
-        columns = <4>;
-
-        map = <
-        RC(0,0) RC(0,1)
-        RC(1,0) RC(1,1)
-        RC(2,0) RC(2,1) RC(2,2)
-        >;
-    };
-
-    direct_matrix_transform: direct_matrix_transform {
-        compatible = "zmk,matrix-transform";
-        rows = <3>;
-        columns = <4>;
-
-        map = <
-        RC(0,0) RC(0,1)
-        RC(0,2) RC(0,3)
-        RC(1,0) RC(1,1) RC(1,2)
-        >;
-    };
-
-    kscan_matrix_comp: kscan_matrix_comp {
-        compatible = "zmk,kscan-composite";
-        rows = <1>;
-        columns = <7>;
-
-        label = "KSCAN_MATRIX_COMP";
-
-        matrix {
-            kscan = <&kscan_matrix>;
-        };
-
-        toggle {
-            kscan = <&kscan_sp3t_toggle>;
-            row-offset = <2>;
-        };
-
-    };
-
-    kscan_direct_comp: kscan_direct_comp {
-        compatible = "zmk,kscan-composite";
-
-        label = "KSCAN_DIRECT_COMP";
-        status = "disabled";
-
-        matrix {
-            kscan = <&kscan_direct>;
-        };
-
-        toggle {
-            kscan = <&kscan_sp3t_toggle>;
-            row-offset = <1>;
-        };
-
-    };
-
-    kscan_matrix: kscan_matrix {
-        compatible = "zmk,kscan-gpio-matrix";
-
-        diode-direction = "col2row";
-
-        col-gpios
-        = <&arduino_header 10 GPIO_ACTIVE_HIGH>
-        , <&arduino_header 9  GPIO_ACTIVE_HIGH>
-        ;
-
-        row-gpios
-        = <&arduino_header 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
-        , <&arduino_header 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
-        ;
-
-    };
-
-    kscan_direct: kscan_direct {
-        compatible = "zmk,kscan-gpio-direct";
-        status = "disabled";
-
-        input-gpios
-        = <&arduino_header 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
-        , <&arduino_header 9  (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
-        , <&arduino_header 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
-        , <&arduino_header 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
-        ;
-
-    };
-
-    kscan_sp3t_toggle: kscan_sp3t_toggle {
-        compatible = "zmk,kscan-gpio-direct";
-        toggle-mode;
-
-        input-gpios
-        = <&arduino_header 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
-        , <&arduino_header 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
-        , <&arduino_header 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
-        ;
-    };
-
-    encoder: encoder {
-        label = "ENCODER";
-        steps = <80>;
-        compatible = "alps,ec11";
-        a-gpios = <&arduino_header 15 GPIO_PULL_UP>;
-        b-gpios = <&arduino_header 14 GPIO_PULL_UP>;
-    };
     sensors {
         compatible = "zmk,keymap-sensors";
         sensors = <&encoder>;
diff --git a/app/boards/shields/zmk_uno/zmk_uno_split.dtsi b/app/boards/shields/zmk_uno/zmk_uno_split.dtsi
new file mode 100644
index 00000000..f84aacc8
--- /dev/null
+++ b/app/boards/shields/zmk_uno/zmk_uno_split.dtsi
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+ #include "zmk_uno.dtsi"
+
+ left_encoder: &encoder {
+    status = "disabled";
+ };
+
+ / {
+    chosen {
+        zmk,matrix-transform = &split_matrix_transform;
+    };
+
+    split_matrix_transform: split_matrix_transform {
+        compatible = "zmk,matrix-transform";
+        rows = <3>;
+        columns = <4>;
+
+        map = <
+        RC(0,0) RC(0,1)
+        RC(1,0) RC(1,1)
+        RC(2,0) RC(2,1) RC(2,2)
+        RC(3,0) RC(3,1)
+        RC(4,0) RC(4,1)
+        RC(5,0) RC(5,1) RC(5,2)
+        >;
+    };
+
+    split_direct_matrix_transform: split_direct_matrix_transform {
+        compatible = "zmk,matrix-transform";
+        rows = <3>;
+        columns = <4>;
+
+        map = <
+        RC(0,0) RC(0,1)
+        RC(0,2) RC(0,3)
+        RC(1,0) RC(1,1) RC(1,2)
+        RC(2,0) RC(2,1)
+        RC(2,2) RC(2,3)
+        RC(3,0) RC(3,1) RC(3,2)
+        >;
+    };
+
+    right_encoder: right_encoder {
+        steps = <80>;
+        status = "disabled";
+        compatible = "alps,ec11";
+        a-gpios = <&arduino_header 15 GPIO_PULL_UP>;
+        b-gpios = <&arduino_header 14 GPIO_PULL_UP>;
+    };
+
+     sensors {
+         compatible = "zmk,keymap-sensors";
+         sensors = <&encoder &right_encoder>;
+         triggers-per-rotation = <20>;
+     };
+ };
diff --git a/app/boards/shields/zmk_uno/zmk_uno_split.keymap b/app/boards/shields/zmk_uno/zmk_uno_split.keymap
new file mode 100644
index 00000000..05f0ffb0
--- /dev/null
+++ b/app/boards/shields/zmk_uno/zmk_uno_split.keymap
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2022 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/backlight.h>
+#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/ext_power.h>
+#include <dt-bindings/zmk/outputs.h>
+#include <dt-bindings/zmk/rgb.h>
+
+// Uncomment the following block if using the "Direct Wire" jumper to switch the matrix to a direct wire.
+
+/* :REMOVE ME
+
+&kscan_direct_comp { status = "okay"; };
+&kscan_direct { status = "okay"; };
+&kscan_matrix_comp { status = "disabled"; };
+&kscan_matrix { status = "disabled"; };
+
+/ {
+    chosen {
+        zmk,matrix-transform = &split_direct_matrix_transform;
+        zmk,kscan = &kscan_direct_comp;
+    };
+};
+
+REMOVE ME: */
+
+
+/ {
+    macros {
+        ZMK_MACRO(ble_zero,
+            wait-ms = <1>;
+            tap-ms = <1>;
+            bindings = <&out OUT_BLE &bt BT_SEL 0>;
+        )
+        ZMK_MACRO(ble_one,
+            wait-ms = <1>;
+            tap-ms = <1>;
+            bindings = <&out OUT_BLE &bt BT_SEL 1>;
+        )
+    };
+
+    keymap {
+        compatible = "zmk,keymap";
+
+        default_layer {
+            bindings = <
+                &kp A &bl BL_TOG
+                &rgb_ug RGB_EFF &bt BT_CLR
+
+                &out OUT_USB &ble_zero &ble_one
+
+                &kp C &kp D
+                &kp E &kp F
+                &none &none &none
+           >;
+
+           sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>;
+        };
+    };
+};
diff --git a/app/boards/shields/zmk_uno/zmk_uno_split_left.conf b/app/boards/shields/zmk_uno/zmk_uno_split_left.conf
new file mode 100644
index 00000000..0c46ea98
--- /dev/null
+++ b/app/boards/shields/zmk_uno/zmk_uno_split_left.conf
@@ -0,0 +1,20 @@
+# Copyright (c) 2022 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+CONFIG_LOG=y
+CONFIG_ZMK_LOG_LEVEL_DBG=y
+
+CONFIG_ZMK_BLE_PASSKEY_ENTRY=n
+
+# Uncomment for Single color backlight
+# CONFIG_ZMK_BACKLIGHT=y
+
+# Uncomment for RGB
+# CONFIG_ZMK_RGB_UNDERGLOW=y
+
+# Uncomment for Display
+# CONFIG_ZMK_DISPLAY=y
+
+# Uncomment these two lines to enable encoder support
+# CONFIG_EC11=y
+# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y
diff --git a/app/boards/shields/zmk_uno/zmk_uno_split_left.overlay b/app/boards/shields/zmk_uno/zmk_uno_split_left.overlay
new file mode 100644
index 00000000..5782e612
--- /dev/null
+++ b/app/boards/shields/zmk_uno/zmk_uno_split_left.overlay
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2022 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "zmk_uno_split.dtsi"
+
+&left_encoder {
+    status = "okay";
+};
diff --git a/app/boards/shields/zmk_uno/zmk_uno_split_right.conf b/app/boards/shields/zmk_uno/zmk_uno_split_right.conf
new file mode 100644
index 00000000..0c46ea98
--- /dev/null
+++ b/app/boards/shields/zmk_uno/zmk_uno_split_right.conf
@@ -0,0 +1,20 @@
+# Copyright (c) 2022 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+CONFIG_LOG=y
+CONFIG_ZMK_LOG_LEVEL_DBG=y
+
+CONFIG_ZMK_BLE_PASSKEY_ENTRY=n
+
+# Uncomment for Single color backlight
+# CONFIG_ZMK_BACKLIGHT=y
+
+# Uncomment for RGB
+# CONFIG_ZMK_RGB_UNDERGLOW=y
+
+# Uncomment for Display
+# CONFIG_ZMK_DISPLAY=y
+
+# Uncomment these two lines to enable encoder support
+# CONFIG_EC11=y
+# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y
diff --git a/app/boards/shields/zmk_uno/zmk_uno_split_right.overlay b/app/boards/shields/zmk_uno/zmk_uno_split_right.overlay
new file mode 100644
index 00000000..9c2e7d7f
--- /dev/null
+++ b/app/boards/shields/zmk_uno/zmk_uno_split_right.overlay
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2022 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "zmk_uno_split.dtsi"
+
+&split_matrix_transform {
+    row-offset = <3>;
+};
+
+&split_direct_matrix_transform {
+    row-offset = <2>;
+};
+
+&right_encoder {
+    status = "okay";
+};
diff --git a/app/boards/shields/zodiark/zodiark.dtsi b/app/boards/shields/zodiark/zodiark.dtsi
index 66ebb7b4..6e91778e 100644
--- a/app/boards/shields/zodiark/zodiark.dtsi
+++ b/app/boards/shields/zodiark/zodiark.dtsi
@@ -33,7 +33,6 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4)      RC(4,5)    RC(4,6)   RC(4,7)      R
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -47,7 +46,6 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4)      RC(4,5)    RC(4,6)   RC(4,7)      R
 
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -56,7 +54,6 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4)      RC(4,5)    RC(4,6)   RC(4,7)      R
 
     right_encoder: encoder_right {
         compatible = "alps,ec11";
-        label = "RIGHT_ENCODER";
         a-gpios = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -76,7 +73,6 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4)      RC(4,5)    RC(4,6)   RC(4,7)      R
     oled: ssd1306@3c {
         compatible = "solomon,ssd1306fb";
         reg = <0x3c>;
-        label = "DISPLAY";
         width = <128>;
         height = <64>;
         segment-offset = <0>;
diff --git a/app/boards/usb_console.dtsi b/app/boards/usb_console.dtsi
index 3cc76ad3..adf3bd19 100644
--- a/app/boards/usb_console.dtsi
+++ b/app/boards/usb_console.dtsi
@@ -14,7 +14,6 @@
 &usbd {
     cdc_acm_uart: cdc_acm_uart {
         compatible = "zephyr,cdc-acm-uart";
-        label = "CDC_ACM_0";
     };
 };
 
diff --git a/app/dts/behaviors/backlight.dtsi b/app/dts/behaviors/backlight.dtsi
index bebd6dfb..54c83ff4 100644
--- a/app/dts/behaviors/backlight.dtsi
+++ b/app/dts/behaviors/backlight.dtsi
@@ -6,9 +6,9 @@
 
  / {
     behaviors {
-        /omit-if-no-ref/ bl: behavior_backlight {
+        // Behavior can be invoked on peripherals, so name must be <= 8 characters.
+        /omit-if-no-ref/ bl: bcklight {
             compatible = "zmk,behavior-backlight";
-            label = "BCKLGHT";
             #binding-cells = <2>;
         };
     };
diff --git a/app/dts/behaviors/bluetooth.dtsi b/app/dts/behaviors/bluetooth.dtsi
index a49ff4d6..40557b7a 100644
--- a/app/dts/behaviors/bluetooth.dtsi
+++ b/app/dts/behaviors/bluetooth.dtsi
@@ -6,9 +6,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ bt: behavior_bluetooth {
+        /omit-if-no-ref/ bt: bluetooth {
             compatible = "zmk,behavior-bluetooth";
-            label = "BLUETOOTH";
             #binding-cells = <2>;
         };
     };
diff --git a/app/dts/behaviors/caps_word.dtsi b/app/dts/behaviors/caps_word.dtsi
index 219300dc..795fbc08 100644
--- a/app/dts/behaviors/caps_word.dtsi
+++ b/app/dts/behaviors/caps_word.dtsi
@@ -8,9 +8,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ caps_word: behavior_caps_word {
+        /omit-if-no-ref/ caps_word: caps_word {
             compatible = "zmk,behavior-caps-word";
-            label = "CAPS_WORD";
             #binding-cells = <0>;
             continue-list = <UNDERSCORE BACKSPACE DELETE>;
         };
diff --git a/app/dts/behaviors/ext_power.dtsi b/app/dts/behaviors/ext_power.dtsi
index f61170dd..2ae1daf8 100644
--- a/app/dts/behaviors/ext_power.dtsi
+++ b/app/dts/behaviors/ext_power.dtsi
@@ -6,9 +6,9 @@
 
 / {
     behaviors {
-        ext_power: behavior_ext_power {
+        // Behavior can be invoked on peripherals, so name must be <= 8 characters.
+        ext_power: extpower {
             compatible = "zmk,behavior-ext-power";
-            label = "EXTPOWER";
             #binding-cells = <1>;
         };
     };
diff --git a/app/dts/behaviors/gresc.dtsi b/app/dts/behaviors/gresc.dtsi
index fa4c685b..59a73291 100644
--- a/app/dts/behaviors/gresc.dtsi
+++ b/app/dts/behaviors/gresc.dtsi
@@ -10,7 +10,6 @@
     behaviors {
         /omit-if-no-ref/ gresc: grave_escape {
             compatible = "zmk,behavior-mod-morph";
-            label = "GRAVE_ESCAPE";
             #binding-cells = <0>;
             bindings = <&kp ESC>, <&kp GRAVE>;
             mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>;
diff --git a/app/dts/behaviors/key_press.dtsi b/app/dts/behaviors/key_press.dtsi
index b0fc2db1..ddaf7eed 100644
--- a/app/dts/behaviors/key_press.dtsi
+++ b/app/dts/behaviors/key_press.dtsi
@@ -7,9 +7,8 @@
 / {
     behaviors {
         /* DEPRECATED: `cp` will be removed in the future */
-        /omit-if-no-ref/ cp: kp: behavior_key_press {
+        /omit-if-no-ref/ cp: kp: key_press {
             compatible = "zmk,behavior-key-press";
-            label = "KEY_PRESS";
             #binding-cells = <1>;
         };
     };
diff --git a/app/dts/behaviors/key_repeat.dtsi b/app/dts/behaviors/key_repeat.dtsi
index 795a77f6..88910f62 100644
--- a/app/dts/behaviors/key_repeat.dtsi
+++ b/app/dts/behaviors/key_repeat.dtsi
@@ -8,9 +8,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ key_repeat: behavior_key_repeat {
+        /omit-if-no-ref/ key_repeat: key_repeat {
             compatible = "zmk,behavior-key-repeat";
-            label = "KEY_REPEAT";
             #binding-cells = <0>;
             usage-pages = <HID_USAGE_KEY>;
         };
diff --git a/app/dts/behaviors/key_toggle.dtsi b/app/dts/behaviors/key_toggle.dtsi
index df581014..a3e3f36f 100644
--- a/app/dts/behaviors/key_toggle.dtsi
+++ b/app/dts/behaviors/key_toggle.dtsi
@@ -6,9 +6,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ kt: behavior_key_toggle {
+        /omit-if-no-ref/ kt: key_toggle {
             compatible = "zmk,behavior-key-toggle";
-            label = "KEY_TOGGLE";
             #binding-cells = <1>;
         };
     };
diff --git a/app/dts/behaviors/layer_tap.dtsi b/app/dts/behaviors/layer_tap.dtsi
index 1d92245c..dc953e93 100644
--- a/app/dts/behaviors/layer_tap.dtsi
+++ b/app/dts/behaviors/layer_tap.dtsi
@@ -6,9 +6,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ lt: behavior_layer_tap {
+        /omit-if-no-ref/ lt: layer_tap {
             compatible = "zmk,behavior-hold-tap";
-            label = "LAYER_TAP";
             #binding-cells = <2>;
             flavor = "tap-preferred";
             tapping-term-ms = <200>;
diff --git a/app/dts/behaviors/macros.dtsi b/app/dts/behaviors/macros.dtsi
index 36b4a8d3..44bc7ab7 100644
--- a/app/dts/behaviors/macros.dtsi
+++ b/app/dts/behaviors/macros.dtsi
@@ -5,10 +5,8 @@
  */
 
 #define MACRO_PLACEHOLDER 0
-#define ZMK_MACRO_STRINGIFY(x) #x
 #define ZMK_MACRO(name,...) \
 name: name { \
-    label = ZMK_MACRO_STRINGIFY(ZM_ ## name); \
     compatible = "zmk,behavior-macro"; \
     #binding-cells = <0>; \
     __VA_ARGS__ \
@@ -16,7 +14,6 @@ name: name { \
 
 #define ZMK_MACRO1(name,...) \
 name: name { \
-    label = ZMK_MACRO_STRINGIFY(ZM_ ## name); \
     compatible = "zmk,behavior-macro-one-param"; \
     #binding-cells = <1>; \
     __VA_ARGS__ \
@@ -24,7 +21,6 @@ name: name { \
 
 #define ZMK_MACRO2(name,...) \
 name: name { \
-    label = ZMK_MACRO_STRINGIFY(ZM_ ## name); \
     compatible = "zmk,behavior-macro-two-param"; \
     #binding-cells = <2>; \
     __VA_ARGS__ \
@@ -32,63 +28,53 @@ name: name { \
 
 / {
     behaviors {
-        macro_tap: macro_control_mode_tap {
+        macro_tap: macro_tap {
             compatible = "zmk,macro-control-mode-tap";
-            label = "MAC_TAP";
             #binding-cells = <0>;
         };
 
-        macro_press: macro_control_mode_press {
+        macro_press: macro_press {
             compatible = "zmk,macro-control-mode-press";
-            label = "MAC_PRESS";
             #binding-cells = <0>;
         };
 
-        macro_release: macro_control_mode_release {
+        macro_release: macro_release {
             compatible = "zmk,macro-control-mode-release";
-            label = "MAC_REL";
             #binding-cells = <0>;
         };
 
-        macro_tap_time: macro_control_tap_time {
+        macro_tap_time: macro_tap_time {
             compatible = "zmk,macro-control-tap-time";
-            label = "MAC_TAP_TIME";
             #binding-cells = <1>;
         };
 
-        macro_wait_time: macro_control_wait_time {
+        macro_wait_time: macro_wait_time {
             compatible = "zmk,macro-control-wait-time";
-            label = "MAC_WAIT_TIME";
             #binding-cells = <1>;
         };
 
         macro_pause_for_release: macro_pause_for_release {
             compatible = "zmk,macro-pause-for-release";
-            label = "MAC_WAIT_REL";
             #binding-cells = <0>;
         };
 
         macro_param_1to1: macro_param_1to1 {
             compatible = "zmk,macro-param-1to1";
-            label = "MAC_PARAM_1TO1";
             #binding-cells = <0>;
         };
 
         macro_param_1to2: macro_param_1to2 {
             compatible = "zmk,macro-param-1to2";
-            label = "MAC_PARAM_1TO2";
             #binding-cells = <0>;
         };
 
         macro_param_2to1: macro_param_2to1 {
             compatible = "zmk,macro-param-2to1";
-            label = "MAC_PARAM_2TO1";
             #binding-cells = <0>;
         };
 
         macro_param_2to2: macro_param_2to2 {
             compatible = "zmk,macro-param-2to2";
-            label = "MAC_PARAM_2TO2";
             #binding-cells = <0>;
         };
     };
diff --git a/app/dts/behaviors/mod_tap.dtsi b/app/dts/behaviors/mod_tap.dtsi
index d441a4f1..38bb34fe 100644
--- a/app/dts/behaviors/mod_tap.dtsi
+++ b/app/dts/behaviors/mod_tap.dtsi
@@ -6,9 +6,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ mt: behavior_mod_tap {
+        /omit-if-no-ref/ mt: mod_tap {
             compatible = "zmk,behavior-hold-tap";
-            label = "MOD_TAP";
             #binding-cells = <2>;
             flavor = "hold-preferred";
             tapping-term-ms = <200>;
diff --git a/app/dts/behaviors/momentary_layer.dtsi b/app/dts/behaviors/momentary_layer.dtsi
index d1c91232..6d85165d 100644
--- a/app/dts/behaviors/momentary_layer.dtsi
+++ b/app/dts/behaviors/momentary_layer.dtsi
@@ -6,9 +6,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ mo: behavior_momentary_layer {
+        /omit-if-no-ref/ mo: momentary_layer {
             compatible = "zmk,behavior-momentary-layer";
-            label = "MO";
             #binding-cells = <1>;
         };
     };
diff --git a/app/dts/behaviors/mouse_key_press.dtsi b/app/dts/behaviors/mouse_key_press.dtsi
index 9cc16e81..975c24aa 100644
--- a/app/dts/behaviors/mouse_key_press.dtsi
+++ b/app/dts/behaviors/mouse_key_press.dtsi
@@ -1,8 +1,7 @@
 / {
     behaviors {
-        /omit-if-no-ref/ mkp: behavior_mouse_key_press {
+        /omit-if-no-ref/ mkp: mouse_key_press {
             compatible = "zmk,behavior-mouse-key-press";
-            label = "MOUSE_KEY_PRESS";
             #binding-cells = <1>;
         };
     };
diff --git a/app/dts/behaviors/none.dtsi b/app/dts/behaviors/none.dtsi
index fc4890c3..13d056f0 100644
--- a/app/dts/behaviors/none.dtsi
+++ b/app/dts/behaviors/none.dtsi
@@ -6,9 +6,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ none: behavior_none {
+        /omit-if-no-ref/ none: none {
             compatible = "zmk,behavior-none";
-            label = "NONE";
             #binding-cells = <0>;
         };
     };
diff --git a/app/dts/behaviors/outputs.dtsi b/app/dts/behaviors/outputs.dtsi
index 88e8f882..f7737196 100644
--- a/app/dts/behaviors/outputs.dtsi
+++ b/app/dts/behaviors/outputs.dtsi
@@ -6,9 +6,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ out: behavior_outputs {
+        /omit-if-no-ref/ out: outputs {
             compatible = "zmk,behavior-outputs";
-            label = "OUTPUTS";
             #binding-cells = <1>;
         };
     };
diff --git a/app/dts/behaviors/reset.dtsi b/app/dts/behaviors/reset.dtsi
index 2e775269..e407b107 100644
--- a/app/dts/behaviors/reset.dtsi
+++ b/app/dts/behaviors/reset.dtsi
@@ -8,15 +8,15 @@
 
 / {
     behaviors {
-        sys_reset: behavior_reset {
+        // Behavior can be invoked on peripherals, so name must be <= 8 characters.
+        sys_reset: sysreset {
             compatible = "zmk,behavior-reset";
-            label = "SYSRESET";
             #binding-cells = <0>;
         };
 
-        bootloader: behavior_reset_dfu {
+        // Behavior can be invoked on peripherals, so name must be <= 8 characters.
+        bootloader: bootload {
             compatible = "zmk,behavior-reset";
-            label = "BOOTLOAD";
             type = <RST_UF2>;
             #binding-cells = <0>;
         };
diff --git a/app/dts/behaviors/rgb_underglow.dtsi b/app/dts/behaviors/rgb_underglow.dtsi
index 6ffec2e6..969518a6 100644
--- a/app/dts/behaviors/rgb_underglow.dtsi
+++ b/app/dts/behaviors/rgb_underglow.dtsi
@@ -6,9 +6,9 @@
 
 / {
     behaviors {
-        rgb_ug: behavior_rgb_underglow {
+        // Behavior can be invoked on peripherals, so name must be <= 8 characters.
+        rgb_ug: rgb_ug {
             compatible = "zmk,behavior-rgb-underglow";
-            label = "RGB_UG";
             #binding-cells = <2>;
         };
     };
diff --git a/app/dts/behaviors/sensor_rotate_key_press.dtsi b/app/dts/behaviors/sensor_rotate_key_press.dtsi
index dc30b798..d9bdbfe5 100644
--- a/app/dts/behaviors/sensor_rotate_key_press.dtsi
+++ b/app/dts/behaviors/sensor_rotate_key_press.dtsi
@@ -7,9 +7,8 @@
 / {
     behaviors {
         /* DEPRECATED: `inc_dec_cp` will be removed in the future */
-        /omit-if-no-ref/ inc_dec_cp: inc_dec_kp: behavior_sensor_rotate_key_press {
+        /omit-if-no-ref/ inc_dec_cp: inc_dec_kp: enc_key_press {
             compatible = "zmk,behavior-sensor-rotate-var";
-            label = "ENC_KEY_PRESS";
             #sensor-binding-cells = <2>;
             bindings = <&kp>, <&kp>;
         };
diff --git a/app/dts/behaviors/sticky_key.dtsi b/app/dts/behaviors/sticky_key.dtsi
index 72a80a90..c8973d4d 100644
--- a/app/dts/behaviors/sticky_key.dtsi
+++ b/app/dts/behaviors/sticky_key.dtsi
@@ -6,17 +6,15 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ sk: behavior_sticky_key {
+        /omit-if-no-ref/ sk: sticky_key {
             compatible = "zmk,behavior-sticky-key";
-            label = "STICKY_KEY";
             #binding-cells = <1>;
             release-after-ms = <1000>;
             bindings = <&kp>;
             ignore-modifiers;
         };
-        /omit-if-no-ref/ sl: behavior_sticky_layer {
+        /omit-if-no-ref/ sl: sticky_layer {
             compatible = "zmk,behavior-sticky-key";
-            label = "STICKY_LAYER";
             #binding-cells = <1>;
             release-after-ms = <1000>;
             bindings = <&mo>;
diff --git a/app/dts/behaviors/to_layer.dtsi b/app/dts/behaviors/to_layer.dtsi
index 0ea66fa9..904f023d 100644
--- a/app/dts/behaviors/to_layer.dtsi
+++ b/app/dts/behaviors/to_layer.dtsi
@@ -6,9 +6,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ to: behavior_to_layer {
+        /omit-if-no-ref/ to: to_layer {
             compatible = "zmk,behavior-to-layer";
-            label = "TO_LAYER";
             #binding-cells = <1>;
         };
     };
diff --git a/app/dts/behaviors/toggle_layer.dtsi b/app/dts/behaviors/toggle_layer.dtsi
index 75730934..05f2988e 100644
--- a/app/dts/behaviors/toggle_layer.dtsi
+++ b/app/dts/behaviors/toggle_layer.dtsi
@@ -6,9 +6,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ tog: behavior_toggle_layer {
+        /omit-if-no-ref/ tog: toggle_layer {
             compatible = "zmk,behavior-toggle-layer";
-            label = "TOGGLE_LAYER";
             #binding-cells = <1>;
         };
     };
diff --git a/app/dts/behaviors/transparent.dtsi b/app/dts/behaviors/transparent.dtsi
index 0dfaade2..3586f02a 100644
--- a/app/dts/behaviors/transparent.dtsi
+++ b/app/dts/behaviors/transparent.dtsi
@@ -6,9 +6,8 @@
 
 / {
     behaviors {
-        /omit-if-no-ref/ trans: behavior_transparent {
+        /omit-if-no-ref/ trans: transparent {
             compatible = "zmk,behavior-transparent";
-            label = "TRANS";
             #binding-cells = <0>;
         };
     };
diff --git a/app/dts/bindings/behaviors/one_param.yaml b/app/dts/bindings/behaviors/one_param.yaml
index faa01a0d..9a503e8a 100644
--- a/app/dts/bindings/behaviors/one_param.yaml
+++ b/app/dts/bindings/behaviors/one_param.yaml
@@ -4,7 +4,8 @@
 properties:
   label:
     type: string
-    required: true
+    required: false
+    deprecated: true
   "#binding-cells":
     type: int
     required: true
diff --git a/app/dts/bindings/behaviors/two_param.yaml b/app/dts/bindings/behaviors/two_param.yaml
index d4cdfaa0..4f342301 100644
--- a/app/dts/bindings/behaviors/two_param.yaml
+++ b/app/dts/bindings/behaviors/two_param.yaml
@@ -4,7 +4,8 @@
 properties:
   label:
     type: string
-    required: true
+    required: false
+    deprecated: true
   "#binding-cells":
     type: int
     required: true
diff --git a/app/dts/bindings/behaviors/zero_param.yaml b/app/dts/bindings/behaviors/zero_param.yaml
index 075270d6..79d0dcae 100644
--- a/app/dts/bindings/behaviors/zero_param.yaml
+++ b/app/dts/bindings/behaviors/zero_param.yaml
@@ -4,7 +4,8 @@
 properties:
   label:
     type: string
-    required: true
+    required: false
+    deprecated: true
   "#binding-cells":
     type: int
     required: true
diff --git a/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-var.yaml b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-var.yaml
index 0da3b4db..d286f9c4 100644
--- a/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-var.yaml
+++ b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-var.yaml
@@ -8,7 +8,8 @@ compatible: "zmk,behavior-sensor-rotate-var"
 properties:
   label:
     type: string
-    required: true
+    required: false
+    deprecated: true
   "#sensor-binding-cells":
     type: int
     required: true
diff --git a/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml
index d20777b8..dbb92c8b 100644
--- a/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml
+++ b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml
@@ -8,7 +8,8 @@ compatible: "zmk,behavior-sensor-rotate"
 properties:
   label:
     type: string
-    required: true
+    required: false
+    deprecated: true
   "#sensor-binding-cells":
     type: int
     required: true
diff --git a/app/dts/bindings/zmk,ext-power-generic.yaml b/app/dts/bindings/zmk,ext-power-generic.yaml
index ddb4b3de..cb2a16b5 100644
--- a/app/dts/bindings/zmk,ext-power-generic.yaml
+++ b/app/dts/bindings/zmk,ext-power-generic.yaml
@@ -14,7 +14,8 @@ properties:
     required: true
   label:
     type: string
-    required: true
+    required: false
+    deprecated: true
   init-delay-ms:
     type: int
     description: Number of milliseconds to delay after initializing driver
diff --git a/app/dts/bindings/zmk,keymap.yaml b/app/dts/bindings/zmk,keymap.yaml
index 56821ded..4c675d21 100644
--- a/app/dts/bindings/zmk,keymap.yaml
+++ b/app/dts/bindings/zmk,keymap.yaml
@@ -7,12 +7,19 @@ child-binding:
   description: "A layer to be used in a keymap"
 
   properties:
-    label:
+    display-name:
       type: string
       required: false
+      description: The name of this layer to show on displays
     bindings:
       type: phandle-array
       required: true
     sensor-bindings:
       type: phandle-array
       required: false
+
+    label:
+      type: string
+      required: false
+      deprecated: true
+      description: Deprecated. Use "name" instead.
diff --git a/app/dts/bindings/zmk,kscan-composite.yaml b/app/dts/bindings/zmk,kscan-composite.yaml
index 6126c303..857ef34f 100644
--- a/app/dts/bindings/zmk,kscan-composite.yaml
+++ b/app/dts/bindings/zmk,kscan-composite.yaml
@@ -6,6 +6,8 @@ compatible: "zmk,kscan-composite"
 properties:
   label:
     type: string
+    required: false
+    deprecated: true
   rows:
     type: int
   columns:
@@ -17,6 +19,8 @@ child-binding:
   properties:
     label:
       type: string
+      required: false
+      deprecated: true
     kscan:
       type: phandle
     row-offset:
diff --git a/app/dts/bindings/zmk,kscan-mock.yaml b/app/dts/bindings/zmk,kscan-mock.yaml
index f9d83fa7..2fe9360c 100644
--- a/app/dts/bindings/zmk,kscan-mock.yaml
+++ b/app/dts/bindings/zmk,kscan-mock.yaml
@@ -6,6 +6,8 @@ compatible: "zmk,kscan-mock"
 properties:
   label:
     type: string
+    required: false
+    deprecated: true
   event-period:
     type: int
     description: Milliseconds between each generated event
diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h
index 066cc723..3936da5e 100644
--- a/app/include/drivers/behavior.h
+++ b/app/include/drivers/behavior.h
@@ -56,6 +56,46 @@ __subsystem struct behavior_driver_api {
  * @endcond
  */
 
+struct zmk_behavior_ref {
+    const struct device *device;
+};
+
+/**
+ * Registers @p node_id as a behavior.
+ */
+#define BEHAVIOR_DEFINE(node_id)                                                                   \
+    static const STRUCT_SECTION_ITERABLE(zmk_behavior_ref,                                         \
+                                         _CONCAT(zmk_behavior_, DEVICE_DT_NAME_GET(node_id))) = {  \
+        .device = DEVICE_DT_GET(node_id),                                                          \
+    }
+
+/**
+ * @brief Like DEVICE_DT_DEFINE(), but also registers the device as a behavior.
+ *
+ * @param node_id The devicetree node identifier.
+ * @param ... Other parameters as expected by DEVICE_DT_DEFINE.
+ */
+#define BEHAVIOR_DT_DEFINE(node_id, ...)                                                           \
+    DEVICE_DT_DEFINE(node_id, __VA_ARGS__);                                                        \
+    BEHAVIOR_DEFINE(node_id)
+
+/**
+ * @brief Like DEVICE_DT_INST_DEFINE(), but also registers the device as a behavior.
+ *
+ * @param inst Instance number.
+ * @param ... Other parameters as expected by DEVICE_DT_DEFINE.
+ */
+#define BEHAVIOR_DT_INST_DEFINE(inst, ...)                                                         \
+    DEVICE_DT_INST_DEFINE(inst, __VA_ARGS__);                                                      \
+    BEHAVIOR_DEFINE(DT_DRV_INST(inst))
+
+/**
+ * Syscall wrapper for zmk_behavior_get_binding().
+ *
+ * Use zmk_behavior_get_binding() in application code instead.
+ */
+__syscall const struct device *behavior_get_binding(const char *name);
+
 /**
  * @brief Handle the keymap binding which needs to be converted from relative "toggle" to absolute
  * "turn on"
@@ -70,7 +110,7 @@ __syscall int behavior_keymap_binding_convert_central_state_dependent_params(
 
 static inline int z_impl_behavior_keymap_binding_convert_central_state_dependent_params(
     struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;
 
     if (api->binding_convert_central_state_dependent_params == NULL) {
@@ -116,7 +156,7 @@ __syscall int behavior_keymap_binding_pressed(struct zmk_behavior_binding *bindi
 
 static inline int z_impl_behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding,
                                                          struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
 
     if (dev == NULL) {
         return -EINVAL;
@@ -144,7 +184,7 @@ __syscall int behavior_keymap_binding_released(struct zmk_behavior_binding *bind
 
 static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_binding *binding,
                                                           struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
 
     if (dev == NULL) {
         return -EINVAL;
@@ -178,7 +218,7 @@ static inline int z_impl_behavior_sensor_keymap_binding_accept_data(
     struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
     const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
     const struct zmk_sensor_channel_data *channel_data) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
 
     if (dev == NULL) {
         return -EINVAL;
@@ -214,7 +254,7 @@ static inline int
 z_impl_behavior_sensor_keymap_binding_process(struct zmk_behavior_binding *binding,
                                               struct zmk_behavior_binding_event event,
                                               enum behavior_sensor_binding_process_mode mode) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
 
     if (dev == NULL) {
         return -EINVAL;
diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h
index 8ca10606..7af89ddb 100644
--- a/app/include/dt-bindings/zmk/bt.h
+++ b/app/include/dt-bindings/zmk/bt.h
@@ -9,6 +9,7 @@
 #define BT_PRV_CMD 2
 #define BT_SEL_CMD 3
 // #define BT_FULL_RESET_CMD   4
+#define BT_DISC_CMD 5
 
 /*
 Note: Some future commands will include additional parameters, so we
@@ -19,3 +20,4 @@ defines these aliases up front.
 #define BT_NXT BT_NXT_CMD 0
 #define BT_PRV BT_PRV_CMD 0
 #define BT_SEL BT_SEL_CMD
+#define BT_DISC BT_DISC_CMD
diff --git a/app/include/linker/zmk-behaviors.ld b/app/include/linker/zmk-behaviors.ld
new file mode 100644
index 00000000..14ecee63
--- /dev/null
+++ b/app/include/linker/zmk-behaviors.ld
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2023 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <zephyr/linker/linker-defs.h>
+
+ITERABLE_SECTION_ROM(zmk_behavior_ref, 4)
diff --git a/app/include/zmk/behavior.h b/app/include/zmk/behavior.h
index 31fb43ed..ab95fd8e 100644
--- a/app/include/zmk/behavior.h
+++ b/app/include/zmk/behavior.h
@@ -6,6 +6,8 @@
 
 #pragma once
 
+#include <zephyr/device.h>
+
 #define ZMK_BEHAVIOR_OPAQUE 0
 #define ZMK_BEHAVIOR_TRANSPARENT 1
 
@@ -19,4 +21,18 @@ struct zmk_behavior_binding_event {
     int layer;
     uint32_t position;
     int64_t timestamp;
-};
\ No newline at end of file
+};
+
+/**
+ * @brief Get a const struct device* for a behavior from its @p name field.
+ *
+ * @param name Behavior name to search for.
+ *
+ * @retval Pointer to the device structure for the behavior with the given name.
+ * @retval NULL if the behavior is not found or its initialization function failed.
+ *
+ * @note This is equivalent to device_get_binding(), except it only searches
+ * behavior devices, so it is faster and there is no chance of it returning an
+ * unrelated node which shares the same name as a behavior.
+ */
+const struct device *zmk_behavior_get_binding(const char *name);
diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h
index 435fde49..4323d098 100644
--- a/app/include/zmk/ble.h
+++ b/app/include/zmk/ble.h
@@ -24,8 +24,10 @@ int zmk_ble_clear_bonds();
 int zmk_ble_prof_next();
 int zmk_ble_prof_prev();
 int zmk_ble_prof_select(uint8_t index);
+int zmk_ble_prof_disconnect(uint8_t index);
 
 int zmk_ble_active_profile_index();
+int zmk_ble_profile_index(const bt_addr_le_t *addr);
 bt_addr_le_t *zmk_ble_active_profile_addr();
 bool zmk_ble_active_profile_is_open();
 bool zmk_ble_active_profile_is_connected();
diff --git a/app/include/zmk/events/hid_indicators_changed.h b/app/include/zmk/events/hid_indicators_changed.h
new file mode 100644
index 00000000..b1fba797
--- /dev/null
+++ b/app/include/zmk/events/hid_indicators_changed.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2022 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#pragma once
+
+#include <zmk/hid_indicators_types.h>
+#include <zmk/event_manager.h>
+
+struct zmk_hid_indicators_changed {
+    zmk_hid_indicators_t indicators;
+};
+
+ZMK_EVENT_DECLARE(zmk_hid_indicators_changed);
diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h
index aeaa69d8..30534b02 100644
--- a/app/include/zmk/hid.h
+++ b/app/include/zmk/hid.h
@@ -17,7 +17,12 @@
 #include <dt-bindings/zmk/hid_usage.h>
 #include <dt-bindings/zmk/hid_usage_pages.h>
 
+#if IS_ENABLED(CONFIG_ZMK_HID_KEYBOARD_NKRO_EXTENDED_REPORT)
+#define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYBOARD_LANG8
+#else
 #define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYPAD_EQUAL
+#endif
+
 #define ZMK_HID_MOUSE_NUM_BUTTONS 0x05
 
 // See https://www.usb.org/sites/default/files/hid1_11.pdf section 6.2.2.4 Main Items
@@ -50,6 +55,7 @@
 #define ZMK_HID_MAIN_VAL_BUFFERED_BYTES (0x01 << 8)
 
 #define ZMK_HID_REPORT_ID_KEYBOARD 0x01
+#define ZMK_HID_REPORT_ID_LEDS 0x01
 #define ZMK_HID_REPORT_ID_CONSUMER 0x02
 #define ZMK_HID_REPORT_ID_MOUSE 0x03
 
@@ -73,6 +79,22 @@ static const uint8_t zmk_hid_report_desc[] = {
     HID_REPORT_COUNT(0x01),
     HID_INPUT(ZMK_HID_MAIN_VAL_CONST | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS),
 
+#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+
+    HID_USAGE_PAGE(HID_USAGE_LED),
+    HID_USAGE_MIN8(HID_USAGE_LED_NUM_LOCK),
+    HID_USAGE_MAX8(HID_USAGE_LED_KANA),
+    HID_REPORT_SIZE(0x01),
+    HID_REPORT_COUNT(0x05),
+    HID_OUTPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS),
+
+    HID_USAGE_PAGE(HID_USAGE_LED),
+    HID_REPORT_SIZE(0x03),
+    HID_REPORT_COUNT(0x01),
+    HID_OUTPUT(ZMK_HID_MAIN_VAL_CONST | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS),
+
+#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+
     HID_USAGE_PAGE(HID_USAGE_KEY),
 
 #if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO)
@@ -189,6 +211,19 @@ struct zmk_hid_keyboard_report {
     struct zmk_hid_keyboard_report_body body;
 } __packed;
 
+#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+
+struct zmk_hid_led_report_body {
+    uint8_t leds;
+} __packed;
+
+struct zmk_hid_led_report {
+    uint8_t report_id;
+    struct zmk_hid_led_report_body body;
+} __packed;
+
+#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+
 struct zmk_hid_consumer_report_body {
 #if IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC)
     uint8_t keys[CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE];
diff --git a/app/include/zmk/hid_indicators.h b/app/include/zmk/hid_indicators.h
new file mode 100644
index 00000000..7c7b89f5
--- /dev/null
+++ b/app/include/zmk/hid_indicators.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2022 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#pragma once
+
+#include <zmk/endpoints_types.h>
+#include <zmk/hid.h>
+#include <zmk/hid_indicators_types.h>
+
+zmk_hid_indicators_t zmk_hid_indicators_get_current_profile(void);
+zmk_hid_indicators_t zmk_hid_indicators_get_profile(struct zmk_endpoint_instance endpoint);
+void zmk_hid_indicators_set_profile(zmk_hid_indicators_t indicators,
+                                    struct zmk_endpoint_instance endpoint);
+
+void zmk_hid_indicators_process_report(struct zmk_hid_led_report_body *report,
+                                       struct zmk_endpoint_instance endpoint);
diff --git a/app/include/zmk/hid_indicators_types.h b/app/include/zmk/hid_indicators_types.h
new file mode 100644
index 00000000..43bcf3c5
--- /dev/null
+++ b/app/include/zmk/hid_indicators_types.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2022 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#pragma once
+
+typedef uint8_t zmk_hid_indicators_t;
diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h
index 9ce140bf..9bf81e1e 100644
--- a/app/include/zmk/keymap.h
+++ b/app/include/zmk/keymap.h
@@ -22,14 +22,14 @@ int zmk_keymap_layer_activate(uint8_t layer);
 int zmk_keymap_layer_deactivate(uint8_t layer);
 int zmk_keymap_layer_toggle(uint8_t layer);
 int zmk_keymap_layer_to(uint8_t layer);
-const char *zmk_keymap_layer_label(uint8_t layer);
+const char *zmk_keymap_layer_name(uint8_t layer);
 
 int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
                                       int64_t timestamp);
 
 #define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst)                                                  \
     {                                                                                              \
-        .behavior_dev = DT_PROP(DT_PHANDLE_BY_IDX(drv_inst, bindings, idx), label),                \
+        .behavior_dev = DEVICE_DT_NAME(DT_PHANDLE_BY_IDX(drv_inst, bindings, idx)),                \
         .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(drv_inst, bindings, idx, param1), (0),        \
                               (DT_PHA_BY_IDX(drv_inst, bindings, idx, param1))),                   \
         .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(drv_inst, bindings, idx, param2), (0),        \
diff --git a/app/include/zmk/split/bluetooth/central.h b/app/include/zmk/split/bluetooth/central.h
index 443d9b1b..4706b3aa 100644
--- a/app/include/zmk/split/bluetooth/central.h
+++ b/app/include/zmk/split/bluetooth/central.h
@@ -4,5 +4,15 @@
 #include <zephyr/bluetooth/addr.h>
 #include <zmk/behavior.h>
 
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+#include <zmk/hid_indicators_types.h>
+#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+
 int zmk_split_bt_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding,
-                                 struct zmk_behavior_binding_event event, bool state);
\ No newline at end of file
+                                 struct zmk_behavior_binding_event event, bool state);
+
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+
+int zmk_split_bt_update_hid_indicator(zmk_hid_indicators_t indicators);
+
+#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
diff --git a/app/include/zmk/split/bluetooth/peripheral.h b/app/include/zmk/split/bluetooth/peripheral.h
index a650508a..44ac8062 100644
--- a/app/include/zmk/split/bluetooth/peripheral.h
+++ b/app/include/zmk/split/bluetooth/peripheral.h
@@ -6,4 +6,6 @@
 
 #pragma once
 
-bool zmk_split_bt_peripheral_is_connected(void);
\ No newline at end of file
+bool zmk_split_bt_peripheral_is_connected(void);
+
+bool zmk_split_bt_peripheral_is_bonded(void);
\ No newline at end of file
diff --git a/app/include/zmk/split/bluetooth/uuid.h b/app/include/zmk/split/bluetooth/uuid.h
index c38131dd..dccdfc80 100644
--- a/app/include/zmk/split/bluetooth/uuid.h
+++ b/app/include/zmk/split/bluetooth/uuid.h
@@ -17,3 +17,4 @@
 #define ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000001)
 #define ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID ZMK_BT_SPLIT_UUID(0x00000002)
 #define ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000003)
+#define ZMK_SPLIT_BT_UPDATE_HID_INDICATORS_UUID ZMK_BT_SPLIT_UUID(0x00000004)
diff --git a/app/cmake/ZephyrBuildConfig.cmake b/app/keymap-module/modules/modules.cmake
similarity index 99%
rename from app/cmake/ZephyrBuildConfig.cmake
rename to app/keymap-module/modules/modules.cmake
index ade34199..e260da8f 100644
--- a/app/cmake/ZephyrBuildConfig.cmake
+++ b/app/keymap-module/modules/modules.cmake
@@ -5,8 +5,6 @@
 #    * single overlay,
 #    * or per board/shield.
 
-cmake_minimum_required(VERSION 3.15)
-
 list(APPEND BOARD_ROOT ${APPLICATION_SOURCE_DIR})
 list(APPEND DTS_ROOT ${APPLICATION_SOURCE_DIR})
 
diff --git a/app/keymap-module/zephyr/module.yml b/app/keymap-module/zephyr/module.yml
new file mode 100644
index 00000000..9daa3a18
--- /dev/null
+++ b/app/keymap-module/zephyr/module.yml
@@ -0,0 +1,5 @@
+# This ensures our modules/modules.cmake file is loaded *after* all the other modules,
+# To set up the various keymap DTS and overridden .conf files are located and chosen.
+build:
+  settings:
+    module_ext_root: "."
diff --git a/app/module/drivers/kscan/CMakeLists.txt b/app/module/drivers/kscan/CMakeLists.txt
index 7ae9524c..5b05af76 100644
--- a/app/module/drivers/kscan/CMakeLists.txt
+++ b/app/module/drivers/kscan/CMakeLists.txt
@@ -1,10 +1,11 @@
-# Copyright (c) 2020 The ZMK Contributors
+# Copyright (c) 2020-2023 The ZMK Contributors
 # SPDX-License-Identifier: MIT
 
 zephyr_library_amend()
 
 zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio.c)
 zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_MATRIX kscan_gpio_matrix.c)
+zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_CHARLIEPLEX kscan_gpio_charlieplex.c)
 zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DIRECT kscan_gpio_direct.c)
 zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DEMUX kscan_gpio_demux.c)
 zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_MOCK_DRIVER kscan_mock.c)
diff --git a/app/module/drivers/kscan/Kconfig b/app/module/drivers/kscan/Kconfig
index 6f60b3f9..6b701936 100644
--- a/app/module/drivers/kscan/Kconfig
+++ b/app/module/drivers/kscan/Kconfig
@@ -5,6 +5,7 @@ DT_COMPAT_ZMK_KSCAN_COMPOSITE := zmk,kscan-composite
 DT_COMPAT_ZMK_KSCAN_GPIO_DEMUX := zmk,kscan-gpio-demux
 DT_COMPAT_ZMK_KSCAN_GPIO_DIRECT := zmk,kscan-gpio-direct
 DT_COMPAT_ZMK_KSCAN_GPIO_MATRIX := zmk,kscan-gpio-matrix
+DT_COMPAT_ZMK_KSCAN_GPIO_CHARLIEPLEX := zmk,kscan-gpio-charlieplex
 DT_COMPAT_ZMK_KSCAN_MOCK := zmk,kscan-mock
 
 if KSCAN
@@ -33,6 +34,11 @@ config ZMK_KSCAN_GPIO_MATRIX
     default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_GPIO_MATRIX))
     select ZMK_KSCAN_GPIO_DRIVER
 
+config ZMK_KSCAN_GPIO_CHARLIEPLEX
+    bool
+    default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_GPIO_CHARLIEPLEX))
+    select ZMK_KSCAN_GPIO_DRIVER
+
 if ZMK_KSCAN_GPIO_MATRIX
 
 config ZMK_KSCAN_MATRIX_WAIT_BEFORE_INPUTS
@@ -58,6 +64,30 @@ config ZMK_KSCAN_MATRIX_WAIT_BETWEEN_OUTPUTS
 
 endif # ZMK_KSCAN_GPIO_MATRIX
 
+if ZMK_KSCAN_GPIO_CHARLIEPLEX
+
+config ZMK_KSCAN_CHARLIEPLEX_WAIT_BEFORE_INPUTS
+    int "Ticks to wait before reading inputs after an output set active"
+    default 0
+    help
+        When iterating over each output to drive it active, read inputs, then set
+        inactive again, some boards may take time for output to propagate to the
+        inputs. In that scenario, set this value to a positive value to configure
+        the number of ticks to wait after setting an output active before reading
+        the inputs for their active state.
+
+config ZMK_KSCAN_CHARLIEPLEX_WAIT_BETWEEN_OUTPUTS
+    int "Ticks to wait between each output when scanning charlieplex matrix"
+    default 0
+    help
+        When iterating over each output to drive it active, read inputs, then set
+        inactive again, some boards may take time for the previous output to
+        "settle" before reading inputs for the next active output column. In that
+        scenario, set this value to a positive value to configure the number of
+        usecs to wait after reading each column of keys.
+
+endif # ZMK_KSCAN_GPIO_CHARLIEPLEX
+
 config ZMK_KSCAN_MOCK_DRIVER
     bool
     default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_MOCK))
diff --git a/app/module/drivers/kscan/kscan_gpio_charlieplex.c b/app/module/drivers/kscan/kscan_gpio_charlieplex.c
new file mode 100644
index 00000000..f450af2b
--- /dev/null
+++ b/app/module/drivers/kscan/kscan_gpio_charlieplex.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2020-2023 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <zmk/debounce.h>
+
+#include <zephyr/device.h>
+#include <zephyr/devicetree.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/drivers/kscan.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+#include <zephyr/sys/__assert.h>
+#include <zephyr/sys/util.h>
+
+LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+
+#define DT_DRV_COMPAT zmk_kscan_gpio_charlieplex
+
+#define INST_LEN(n) DT_INST_PROP_LEN(n, gpios)
+#define INST_CHARLIEPLEX_LEN(n) (INST_LEN(n) * INST_LEN(n))
+
+#if CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS >= 0
+#define INST_DEBOUNCE_PRESS_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS
+#else
+#define INST_DEBOUNCE_PRESS_MS(n)                                                                  \
+    DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_press_ms))
+#endif
+
+#if CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS >= 0
+#define INST_DEBOUNCE_RELEASE_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS
+#else
+#define INST_DEBOUNCE_RELEASE_MS(n)                                                                \
+    DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_release_ms))
+#endif
+
+#define KSCAN_GPIO_CFG_INIT(idx, inst_idx)                                                         \
+    GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst_idx), gpios, idx)
+
+#define INST_INTR_DEFINED(n) DT_INST_NODE_HAS_PROP(n, interrupt_gpios)
+
+#define WITH_INTR(n) COND_CODE_1(INST_INTR_DEFINED(n), (+1), (+0))
+#define WITHOUT_INTR(n) COND_CODE_0(INST_INTR_DEFINED(n), (+1), (+0))
+
+#define USES_POLLING DT_INST_FOREACH_STATUS_OKAY(WITHOUT_INTR) > 0
+#define USES_INTERRUPT DT_INST_FOREACH_STATUS_OKAY(WITH_INTR) > 0
+
+#if USES_POLLING && USES_INTERRUPT
+#define USES_POLL_AND_INTR 1
+#else
+#define USES_POLL_AND_INTR 0
+#endif
+
+#define COND_ANY_POLLING(code) COND_CODE_1(USES_POLLING, code, ())
+#define COND_POLL_AND_INTR(code) COND_CODE_1(USES_POLL_AND_INTR, code, ())
+#define COND_THIS_INTERRUPT(n, code) COND_CODE_1(INST_INTR_DEFINED(n), code, ())
+
+#define KSCAN_INTR_CFG_INIT(inst_idx) GPIO_DT_SPEC_GET(DT_DRV_INST(inst_idx), interrupt_gpios)
+
+struct kscan_charlieplex_data {
+    const struct device *dev;
+    kscan_callback_t callback;
+    struct k_work_delayable work;
+    int64_t scan_time; /* Timestamp of the current or scheduled scan. */
+    struct gpio_callback irq_callback;
+    /**
+     * Current state of the matrix as a flattened 2D array of length
+     * (config->cells.length ^2)
+     */
+    struct zmk_debounce_state *charlieplex_state;
+};
+
+struct kscan_gpio_list {
+    const struct gpio_dt_spec *gpios;
+    size_t len;
+};
+
+/** Define a kscan_gpio_list from a compile-time GPIO array. */
+#define KSCAN_GPIO_LIST(gpio_array)                                                                \
+    ((struct kscan_gpio_list){.gpios = gpio_array, .len = ARRAY_SIZE(gpio_array)})
+
+struct kscan_charlieplex_config {
+    struct kscan_gpio_list cells;
+    struct zmk_debounce_config debounce_config;
+    int32_t debounce_scan_period_ms;
+    int32_t poll_period_ms;
+    bool use_interrupt;
+    const struct gpio_dt_spec interrupt;
+};
+
+/**
+ * Get the index into a matrix state array from a row and column.
+ * There are effectively (n) cols and (n-1) rows, but we use the full col x row space
+ * as a safety measure against someone accidentally defining a transform RC at (p,p)
+ */
+static int state_index(const struct kscan_charlieplex_config *config, const int row,
+                       const int col) {
+    __ASSERT(row < config->cells.len, "Invalid row %i", row);
+    __ASSERT(col < config->cells.len, "Invalid column %i", col);
+    __ASSERT(col != row, "Invalid column row pair %i, %i", col, row);
+
+    return (col * config->cells.len) + row;
+}
+
+static int kscan_charlieplex_set_as_input(const struct gpio_dt_spec *gpio) {
+    if (!device_is_ready(gpio->port)) {
+        LOG_ERR("GPIO is not ready: %s", gpio->port->name);
+        return -ENODEV;
+    }
+
+    gpio_flags_t pull_flag =
+        ((gpio->dt_flags & GPIO_ACTIVE_LOW) == GPIO_ACTIVE_LOW) ? GPIO_PULL_UP : GPIO_PULL_DOWN;
+
+    int err = gpio_pin_configure_dt(gpio, GPIO_INPUT | pull_flag);
+    if (err) {
+        LOG_ERR("Unable to configure pin %u on %s for input", gpio->pin, gpio->port->name);
+        return err;
+    }
+    return 0;
+}
+
+static int kscan_charlieplex_set_as_output(const struct gpio_dt_spec *gpio) {
+    if (!device_is_ready(gpio->port)) {
+        LOG_ERR("GPIO is not ready: %s", gpio->port->name);
+        return -ENODEV;
+    }
+
+    int err = gpio_pin_configure_dt(gpio, GPIO_OUTPUT);
+    if (err) {
+        LOG_ERR("Unable to configure pin %u on %s for output", gpio->pin, gpio->port->name);
+        return err;
+    }
+
+    err = gpio_pin_set_dt(gpio, 1);
+    if (err) {
+        LOG_ERR("Failed to set output pin %u active: %i", gpio->pin, err);
+    }
+    return err;
+}
+
+static int kscan_charlieplex_set_all_as_input(const struct device *dev) {
+    const struct kscan_charlieplex_config *config = dev->config;
+    int err = 0;
+    for (int i = 0; i < config->cells.len; i++) {
+        err = kscan_charlieplex_set_as_input(&config->cells.gpios[i]);
+        if (err) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+static int kscan_charlieplex_set_all_outputs(const struct device *dev, const int value) {
+    const struct kscan_charlieplex_config *config = dev->config;
+
+    for (int i = 0; i < config->cells.len; i++) {
+        const struct gpio_dt_spec *gpio = &config->cells.gpios[i];
+        int err = gpio_pin_configure_dt(gpio, GPIO_OUTPUT);
+        if (err) {
+            LOG_ERR("Unable to configure pin %u on %s for input", gpio->pin, gpio->port->name);
+            return err;
+        }
+
+        err = gpio_pin_set_dt(gpio, value);
+        if (err) {
+            LOG_ERR("Failed to set output %i to %i: %i", i, value, err);
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+static int kscan_charlieplex_interrupt_configure(const struct device *dev,
+                                                 const gpio_flags_t flags) {
+    const struct kscan_charlieplex_config *config = dev->config;
+    const struct gpio_dt_spec *gpio = &config->interrupt;
+
+    int err = gpio_pin_interrupt_configure_dt(gpio, flags);
+    if (err) {
+        LOG_ERR("Unable to configure interrupt for pin %u on %s", gpio->pin, gpio->port->name);
+        return err;
+    }
+
+    return 0;
+}
+
+static int kscan_charlieplex_interrupt_enable(const struct device *dev) {
+    int err = kscan_charlieplex_interrupt_configure(dev, GPIO_INT_LEVEL_ACTIVE);
+    if (err) {
+        return err;
+    }
+
+    // While interrupts are enabled, set all outputs active so an pressed key will trigger
+    return kscan_charlieplex_set_all_outputs(dev, 1);
+}
+
+static void kscan_charlieplex_irq_callback(const struct device *port, struct gpio_callback *cb,
+                                           const gpio_port_pins_t _pin) {
+    struct kscan_charlieplex_data *data =
+        CONTAINER_OF(cb, struct kscan_charlieplex_data, irq_callback);
+
+    // Disable our interrupt to avoid re-entry while we scan.
+    kscan_charlieplex_interrupt_configure(data->dev, GPIO_INT_DISABLE);
+    data->scan_time = k_uptime_get();
+    k_work_reschedule(&data->work, K_NO_WAIT);
+}
+
+static void kscan_charlieplex_read_continue(const struct device *dev) {
+    const struct kscan_charlieplex_config *config = dev->config;
+    struct kscan_charlieplex_data *data = dev->data;
+
+    data->scan_time += config->debounce_scan_period_ms;
+
+    k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time));
+}
+
+static void kscan_charlieplex_read_end(const struct device *dev) {
+    struct kscan_charlieplex_data *data = dev->data;
+    const struct kscan_charlieplex_config *config = dev->config;
+
+    if (config->use_interrupt) {
+        // Return to waiting for an interrupt.
+        kscan_charlieplex_interrupt_enable(dev);
+    } else {
+        data->scan_time += config->poll_period_ms;
+
+        // Return to polling slowly.
+        k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time));
+    }
+}
+
+static int kscan_charlieplex_read(const struct device *dev) {
+    struct kscan_charlieplex_data *data = dev->data;
+    const struct kscan_charlieplex_config *config = dev->config;
+    bool continue_scan = false;
+
+    // NOTE: RR vs MATRIX: set all pins as input, in case there was a failure on a
+    // previous scan, and one of the pins is still set as output
+    int err = kscan_charlieplex_set_all_as_input(dev);
+    if (err) {
+        return err;
+    }
+
+    // Scan the matrix.
+    for (int row = 0; row < config->cells.len; row++) {
+        const struct gpio_dt_spec *out_gpio = &config->cells.gpios[row];
+        err = kscan_charlieplex_set_as_output(out_gpio);
+        if (err) {
+            return err;
+        }
+
+#if CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BEFORE_INPUTS > 0
+        k_busy_wait(CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BEFORE_INPUTS);
+#endif
+
+        for (int col = 0; col < config->cells.len; col++) {
+            if (col == row) {
+                continue; // pin can't drive itself
+            }
+            const struct gpio_dt_spec *in_gpio = &config->cells.gpios[col];
+            const int index = state_index(config, row, col);
+
+            struct zmk_debounce_state *state = &data->charlieplex_state[index];
+            zmk_debounce_update(state, gpio_pin_get_dt(in_gpio), config->debounce_scan_period_ms,
+                                &config->debounce_config);
+
+            // NOTE: RR vs MATRIX: because we don't need an input/output => row/column
+            // setup, we can update in the same loop.
+            if (zmk_debounce_get_changed(state)) {
+                const bool pressed = zmk_debounce_is_pressed(state);
+
+                LOG_DBG("Sending event at %i,%i state %s", row, col, pressed ? "on" : "off");
+                data->callback(dev, row, col, pressed);
+            }
+            continue_scan = continue_scan || zmk_debounce_is_active(state);
+        }
+
+        err = kscan_charlieplex_set_as_input(out_gpio);
+        if (err) {
+            return err;
+        }
+#if CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BETWEEN_OUTPUTS > 0
+        k_busy_wait(CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BETWEEN_OUTPUTS);
+#endif
+    }
+
+    if (continue_scan) {
+        // At least one key is pressed or the debouncer has not yet decided if
+        // it is pressed. Poll quickly until everything is released.
+        kscan_charlieplex_read_continue(dev);
+    } else {
+        // All keys are released. Return to normal.
+        kscan_charlieplex_read_end(dev);
+    }
+
+    return 0;
+}
+
+static void kscan_charlieplex_work_handler(struct k_work *work) {
+    struct k_work_delayable *dwork = CONTAINER_OF(work, struct k_work_delayable, work);
+    struct kscan_charlieplex_data *data = CONTAINER_OF(dwork, struct kscan_charlieplex_data, work);
+    kscan_charlieplex_read(data->dev);
+}
+
+static int kscan_charlieplex_configure(const struct device *dev, const kscan_callback_t callback) {
+    if (!callback) {
+        return -EINVAL;
+    }
+
+    struct kscan_charlieplex_data *data = dev->data;
+    data->callback = callback;
+    return 0;
+}
+
+static int kscan_charlieplex_enable(const struct device *dev) {
+    struct kscan_charlieplex_data *data = dev->data;
+    data->scan_time = k_uptime_get();
+
+    // Read will automatically start interrupts/polling once done.
+    return kscan_charlieplex_read(dev);
+}
+
+static int kscan_charlieplex_disable(const struct device *dev) {
+    struct kscan_charlieplex_data *data = dev->data;
+    k_work_cancel_delayable(&data->work);
+
+    const struct kscan_charlieplex_config *config = dev->config;
+    if (config->use_interrupt) {
+        return kscan_charlieplex_interrupt_configure(dev, GPIO_INT_DISABLE);
+    }
+    return 0;
+}
+
+static int kscan_charlieplex_init_inputs(const struct device *dev) {
+    const struct kscan_charlieplex_config *config = dev->config;
+
+    for (int i = 0; i < config->cells.len; i++) {
+        int err = kscan_charlieplex_set_as_input(&config->cells.gpios[i]);
+        if (err) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+static int kscan_charlieplex_init_interrupt(const struct device *dev) {
+    struct kscan_charlieplex_data *data = dev->data;
+
+    const struct kscan_charlieplex_config *config = dev->config;
+    const struct gpio_dt_spec *gpio = &config->interrupt;
+    int err = kscan_charlieplex_set_as_input(gpio);
+    if (err) {
+        return err;
+    }
+
+    gpio_init_callback(&data->irq_callback, kscan_charlieplex_irq_callback, BIT(gpio->pin));
+    err = gpio_add_callback(gpio->port, &data->irq_callback);
+    if (err) {
+        LOG_ERR("Error adding the callback to the input device: %i", err);
+    }
+    return err;
+}
+
+static int kscan_charlieplex_init(const struct device *dev) {
+    struct kscan_charlieplex_data *data = dev->data;
+
+    data->dev = dev;
+
+    kscan_charlieplex_init_inputs(dev);
+    kscan_charlieplex_set_all_outputs(dev, 0);
+
+    const struct kscan_charlieplex_config *config = dev->config;
+    if (config->use_interrupt) {
+        kscan_charlieplex_init_interrupt(dev);
+    }
+    k_work_init_delayable(&data->work, kscan_charlieplex_work_handler);
+    return 0;
+}
+
+static const struct kscan_driver_api kscan_charlieplex_api = {
+    .config = kscan_charlieplex_configure,
+    .enable_callback = kscan_charlieplex_enable,
+    .disable_callback = kscan_charlieplex_disable,
+};
+
+#define KSCAN_CHARLIEPLEX_INIT(n)                                                                  \
+    BUILD_ASSERT(INST_DEBOUNCE_PRESS_MS(n) <= DEBOUNCE_COUNTER_MAX,                                \
+                 "ZMK_KSCAN_DEBOUNCE_PRESS_MS or debounce-press-ms is too large");                 \
+    BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(n) <= DEBOUNCE_COUNTER_MAX,                              \
+                 "ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large");             \
+                                                                                                   \
+    static struct zmk_debounce_state kscan_charlieplex_state_##n[INST_CHARLIEPLEX_LEN(n)];         \
+    static const struct gpio_dt_spec kscan_charlieplex_cells_##n[] = {                             \
+        LISTIFY(INST_LEN(n), KSCAN_GPIO_CFG_INIT, (, ), n)};                                       \
+    static struct kscan_charlieplex_data kscan_charlieplex_data_##n = {                            \
+        .charlieplex_state = kscan_charlieplex_state_##n,                                          \
+    };                                                                                             \
+                                                                                                   \
+    static struct kscan_charlieplex_config kscan_charlieplex_config_##n = {                        \
+        .cells = KSCAN_GPIO_LIST(kscan_charlieplex_cells_##n),                                     \
+        .debounce_config =                                                                         \
+            {                                                                                      \
+                .debounce_press_ms = INST_DEBOUNCE_PRESS_MS(n),                                    \
+                .debounce_release_ms = INST_DEBOUNCE_RELEASE_MS(n),                                \
+            },                                                                                     \
+        .debounce_scan_period_ms = DT_INST_PROP(n, debounce_scan_period_ms),                       \
+        COND_ANY_POLLING((.poll_period_ms = DT_INST_PROP(n, poll_period_ms), ))                    \
+            COND_POLL_AND_INTR((.use_interrupt = INST_INTR_DEFINED(n), ))                          \
+                COND_THIS_INTERRUPT(n, (.interrupt = KSCAN_INTR_CFG_INIT(n), ))};                  \
+                                                                                                   \
+    DEVICE_DT_INST_DEFINE(n, &kscan_charlieplex_init, NULL, &kscan_charlieplex_data_##n,           \
+                          &kscan_charlieplex_config_##n, APPLICATION,                              \
+                          CONFIG_APPLICATION_INIT_PRIORITY, &kscan_charlieplex_api);
+
+DT_INST_FOREACH_STATUS_OKAY(KSCAN_CHARLIEPLEX_INIT);
diff --git a/app/module/dts/bindings/kscan/zmk,kscan-gpio-charlieplex.yaml b/app/module/dts/bindings/kscan/zmk,kscan-gpio-charlieplex.yaml
new file mode 100644
index 00000000..f8da1d27
--- /dev/null
+++ b/app/module/dts/bindings/kscan/zmk,kscan-gpio-charlieplex.yaml
@@ -0,0 +1,31 @@
+# Copyright (c) 2023 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+description: GPIO keyboard charlieplex matrix controller
+
+compatible: "zmk,kscan-gpio-charlieplex"
+
+include: kscan.yaml
+
+properties:
+  gpios:
+    type: phandle-array
+    required: true
+  interrupt-gpios:
+    type: phandle-array
+  debounce-press-ms:
+    type: int
+    default: 5
+    description: Debounce time for key press in milliseconds. Use 0 for eager debouncing.
+  debounce-release-ms:
+    type: int
+    default: 5
+    description: Debounce time for key release in milliseconds.
+  debounce-scan-period-ms:
+    type: int
+    default: 1
+    description: Time between reads in milliseconds when any key is pressed.
+  poll-period-ms:
+    type: int
+    default: 1
+    description: Time between reads in milliseconds
diff --git a/app/module/dts/bindings/sensor/alps,ec11.yaml b/app/module/dts/bindings/sensor/alps,ec11.yaml
index 3672ea30..46dad31d 100644
--- a/app/module/dts/bindings/sensor/alps,ec11.yaml
+++ b/app/module/dts/bindings/sensor/alps,ec11.yaml
@@ -6,7 +6,8 @@ compatible: "alps,ec11"
 properties:
   label:
     type: string
-    required: true
+    required: false
+    deprecated: true
   a-gpios:
     type: phandle-array
     required: true
diff --git a/app/run-ble-test.sh b/app/run-ble-test.sh
new file mode 100755
index 00000000..9984caa1
--- /dev/null
+++ b/app/run-ble-test.sh
@@ -0,0 +1,107 @@
+#!/bin/bash
+
+# Copyright (c) 2023 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+if [ -z "$1" ]; then
+    echo "Usage: ./run-ble-test.sh <path to testcase>"
+    exit 1
+fi
+
+path=$1
+if [ "$path" = "all" ]; then
+    path="tests"
+fi
+
+if [ -z "${BSIM_OUT_PATH}" ]; then
+    echo "BSIM_OUT_PATH needs to be set before running this script."
+    exit 1
+fi
+
+if [ -z "$BLE_TESTS_NO_CENTRAL_BUILD" ]; then
+    if ! [ -e build/tests/ble/central ]; then
+        west build -d build/tests/ble/central -b nrf52_bsim tests/ble/central > /dev/null 2>&1
+    else
+        west build -d build/tests/ble/central
+    fi
+
+    cp build/tests/ble/central/zephyr/zephyr.exe "${BSIM_OUT_PATH}/bin/ble_test_central.exe"
+
+    if ! [ -e build/tests/ble/private_central ]; then
+        west build -d build/tests/ble/private_central -b nrf52_bsim tests/ble/central -- -DCONFIG_BT_PRIVACY=y -DCONFIG_BT_SCAN_WITH_IDENTITY=n > /dev/null 2>&1
+    else
+        west build -d build/tests/ble/private_central
+    fi
+
+    cp build/tests/ble/private_central/zephyr/zephyr.exe "${BSIM_OUT_PATH}/bin/ble_test_private_central.exe"
+fi
+
+testcases=$(find $path -name nrf52_bsim.keymap -exec dirname \{\} \;)
+num_cases=$(echo "$testcases" | wc -l)
+if [ $num_cases -gt 1 ] || [ "$testcases" != "${path%%/}" ]; then
+    echo "$testcases"
+    echo "" > ./build/tests/pass-fail.log
+    echo "$testcases" | BLE_TESTS_QUIET_OUTPUT=y BLE_TESTS_NO_CENTRAL_BUILD=y xargs -L 1 -P ${J:-4} ./run-ble-test.sh
+    err=$?
+    sort -k2 ./build/tests/pass-fail.log
+    exit $err
+fi
+
+testcase="$path"
+echo "Running $testcase:"
+
+west build -d build/$testcase -b nrf52_bsim -- -DZMK_CONFIG="$(pwd)/$testcase" > /dev/null 2>&1
+if [ $? -gt 0 ]; then
+    echo "FAILED: $testcase did not build" | tee -a ./build/tests/pass-fail.log
+    exit 1
+fi
+
+if [ -n "${BLE_TESTS_QUIET_OUTPUT}" ]; then
+    output_dev="/dev/null"
+else
+    output_dev="/dev/stdout"
+fi
+
+exe_name=${testcase//\//_}
+
+start_dir=$(pwd)
+cp build/$testcase/zephyr/zmk.exe "${BSIM_OUT_PATH}/bin/${exe_name}"
+pushd "${BSIM_OUT_PATH}/bin" > /dev/null 2>&1
+if [ -e "${start_dir}/build/$testcase/output.log" ]; then
+  rm "${start_dir}/build/$testcase/output.log"
+fi
+
+central_counts=$(wc -l ${start_dir}/${testcase}/centrals.txt | cut -d' ' -f1)
+./${exe_name} -d=0 -s=${exe_name} | tee -a "${start_dir}/build/$testcase/output.log" > "${output_dev}" &
+./bs_device_handbrake -s=${exe_name} -d=1 -r=10 > "${output_dev}" &
+
+cat "${start_dir}/${testcase}/centrals.txt" |
+while IFS= read -r line
+do
+  ${line} -s=${exe_name} | tee -a "${start_dir}/build/$testcase/output.log" > "${output_dev}" &
+done
+
+./bs_2G4_phy_v1 -s=${exe_name} -D=$(( 2 + central_counts )) -sim_length=50e6 > "${output_dev}" 2>&1
+
+popd > /dev/null 2>&1
+
+cat build/$testcase/output.log | sed -E -n -f $testcase/events.patterns > build/$testcase/filtered_output.log
+
+diff -auZ $testcase/snapshot.log build/$testcase/filtered_output.log
+if [ $? -gt 0 ]; then
+    if [ -f $testcase/pending ]; then
+        echo "PENDING: $testcase" | tee -a ./build/tests/pass-fail.log
+        exit 0
+    fi
+
+    if [ -n "${ZMK_TESTS_AUTO_ACCEPT}" ]; then
+        echo "Auto-accepting failure for $testcase"
+        cp build/$testcase/filtered_output.log $testcase/snapshot.log
+    else
+        echo "FAILED: $testcase" | tee -a ./build/tests/pass-fail.log
+        exit 1
+    fi
+fi
+
+echo "PASS: $testcase" | tee -a ./build/tests/pass-fail.log
+exit 0
diff --git a/app/run-test.sh b/app/run-test.sh
index 6935f2c8..cfd37668 100755
--- a/app/run-test.sh
+++ b/app/run-test.sh
@@ -39,8 +39,15 @@ if [ $? -gt 0 ]; then
         echo "PENDING: $testcase" | tee -a ./build/tests/pass-fail.log
         exit 0
     fi
-    echo "FAILED: $testcase" | tee -a ./build/tests/pass-fail.log
-    exit 1
+
+
+    if [ -n "${ZMK_TESTS_AUTO_ACCEPT}" ]; then
+        echo "Auto-accepting failure for $testcase"
+        cp build/$testcase/keycode_events.log $testcase/keycode_events.snapshot
+    else
+        echo "FAILED: $testcase" | tee -a ./build/tests/pass-fail.log
+        exit 1
+    fi
 fi
 
 echo "PASS: $testcase" | tee -a ./build/tests/pass-fail.log
diff --git a/app/src/battery.c b/app/src/battery.c
index c6466272..e76797ef 100644
--- a/app/src/battery.c
+++ b/app/src/battery.c
@@ -18,6 +18,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
 #include <zmk/event_manager.h>
 #include <zmk/battery.h>
 #include <zmk/events/battery_state_changed.h>
+#include <zmk/events/activity_state_changed.h>
+#include <zmk/activity.h>
 #include <zmk/workqueue.h>
 
 static uint8_t last_state_of_charge = 0;
@@ -84,6 +86,10 @@ static void zmk_battery_timer(struct k_timer *timer) {
 
 K_TIMER_DEFINE(battery_timer, zmk_battery_timer, NULL);
 
+static void zmk_battery_start_reporting() {
+    k_timer_start(&battery_timer, K_NO_WAIT, K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL));
+}
+
 static int zmk_battery_init(const struct device *_arg) {
 #if !DT_HAS_CHOSEN(zmk_battery)
     battery = device_get_binding("BATTERY");
@@ -100,9 +106,30 @@ static int zmk_battery_init(const struct device *_arg) {
         return -ENODEV;
     }
 
-    k_timer_start(&battery_timer, K_NO_WAIT, K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL));
-
+    zmk_battery_start_reporting();
     return 0;
 }
 
+static int battery_event_listener(const zmk_event_t *eh) {
+
+    if (as_zmk_activity_state_changed(eh)) {
+        switch (zmk_activity_get_state()) {
+        case ZMK_ACTIVITY_ACTIVE:
+            zmk_battery_start_reporting();
+            return 0;
+        case ZMK_ACTIVITY_IDLE:
+        case ZMK_ACTIVITY_SLEEP:
+            k_timer_stop(&battery_timer);
+            return 0;
+        default:
+            break;
+        }
+    }
+    return -ENOTSUP;
+}
+
+ZMK_LISTENER(battery, battery_event_listener);
+
+ZMK_SUBSCRIPTION(battery, zmk_activity_state_changed);
+
 SYS_INIT(zmk_battery_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
diff --git a/app/src/behavior.c b/app/src/behavior.c
new file mode 100644
index 00000000..fd2b0ec1
--- /dev/null
+++ b/app/src/behavior.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2023 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <zephyr/device.h>
+#include <zephyr/init.h>
+#include <zephyr/sys/util_macro.h>
+#include <string.h>
+
+#include <drivers/behavior.h>
+#include <zmk/behavior.h>
+
+#include <zephyr/logging/log.h>
+LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+
+const struct device *zmk_behavior_get_binding(const char *name) {
+    return behavior_get_binding(name);
+}
+
+const struct device *z_impl_behavior_get_binding(const char *name) {
+    if (name == NULL || name[0] == '\0') {
+        return NULL;
+    }
+
+    STRUCT_SECTION_FOREACH(zmk_behavior_ref, item) {
+        if (z_device_is_ready(item->device) && item->device->name == name) {
+            return item->device;
+        }
+    }
+
+    STRUCT_SECTION_FOREACH(zmk_behavior_ref, item) {
+        if (z_device_is_ready(item->device) && strcmp(item->device->name, name) == 0) {
+            return item->device;
+        }
+    }
+
+    return NULL;
+}
+
+#if IS_ENABLED(CONFIG_LOG)
+static int check_behavior_names(const struct device *dev) {
+    ARG_UNUSED(dev);
+
+    // Behavior names must be unique, but we don't have a good way to enforce this
+    // at compile time, so log an error at runtime if they aren't unique.
+    ptrdiff_t count;
+    STRUCT_SECTION_COUNT(zmk_behavior_ref, &count);
+
+    for (ptrdiff_t i = 0; i < count; i++) {
+        const struct zmk_behavior_ref *current;
+        STRUCT_SECTION_GET(zmk_behavior_ref, i, &current);
+
+        for (ptrdiff_t j = i + 1; j < count; j++) {
+            const struct zmk_behavior_ref *other;
+            STRUCT_SECTION_GET(zmk_behavior_ref, j, &other);
+
+            if (strcmp(current->device->name, other->device->name) == 0) {
+                LOG_ERR("Multiple behaviors have the same name '%s'", current->device->name);
+            }
+        }
+    }
+
+    return 0;
+}
+
+SYS_INIT(check_behavior_names, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
+#endif // IS_ENABLED(CONFIG_LOG)
diff --git a/app/src/behaviors/behavior_backlight.c b/app/src/behaviors/behavior_backlight.c
index fe2155b7..42967e39 100644
--- a/app/src/behaviors/behavior_backlight.c
+++ b/app/src/behaviors/behavior_backlight.c
@@ -91,7 +91,7 @@ static const struct behavior_driver_api behavior_backlight_driver_api = {
     .locality = BEHAVIOR_LOCALITY_GLOBAL,
 };
 
-DEVICE_DT_INST_DEFINE(0, behavior_backlight_init, NULL, NULL, NULL, APPLICATION,
-                      CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_backlight_driver_api);
+BEHAVIOR_DT_INST_DEFINE(0, behavior_backlight_init, NULL, NULL, NULL, APPLICATION,
+                        CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_backlight_driver_api);
 
 #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c
index 6d44b5f5..18a626b9 100644
--- a/app/src/behaviors/behavior_bt.c
+++ b/app/src/behaviors/behavior_bt.c
@@ -31,6 +31,8 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
         return zmk_ble_prof_prev();
     case BT_SEL_CMD:
         return zmk_ble_prof_select(binding->param2);
+    case BT_DISC_CMD:
+        return zmk_ble_prof_disconnect(binding->param2);
     default:
         LOG_ERR("Unknown BT command: %d", binding->param1);
     }
@@ -50,7 +52,7 @@ static const struct behavior_driver_api behavior_bt_driver_api = {
     .binding_released = on_keymap_binding_released,
 };
 
-DEVICE_DT_INST_DEFINE(0, behavior_bt_init, NULL, NULL, NULL, APPLICATION,
-                      CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_bt_driver_api);
+BEHAVIOR_DT_INST_DEFINE(0, behavior_bt_init, NULL, NULL, NULL, APPLICATION,
+                        CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_bt_driver_api);
 
 #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
diff --git a/app/src/behaviors/behavior_caps_word.c b/app/src/behaviors/behavior_caps_word.c
index 4c9fd711..53ea489f 100644
--- a/app/src/behaviors/behavior_caps_word.c
+++ b/app/src/behaviors/behavior_caps_word.c
@@ -55,7 +55,7 @@ static void deactivate_caps_word(const struct device *dev) {
 
 static int on_caps_word_binding_pressed(struct zmk_behavior_binding *binding,
                                         struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     struct behavior_caps_word_data *data = dev->data;
 
     if (data->active) {
@@ -181,9 +181,9 @@ static int behavior_caps_word_init(const struct device *dev) {
         .continuations = {LISTIFY(DT_INST_PROP_LEN(n, continue_list), BREAK_ITEM, (, ), n)},       \
         .continuations_count = DT_INST_PROP_LEN(n, continue_list),                                 \
     };                                                                                             \
-    DEVICE_DT_INST_DEFINE(n, behavior_caps_word_init, NULL, &behavior_caps_word_data_##n,          \
-                          &behavior_caps_word_config_##n, APPLICATION,                             \
-                          CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_caps_word_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_caps_word_init, NULL, &behavior_caps_word_data_##n,        \
+                            &behavior_caps_word_config_##n, APPLICATION,                           \
+                            CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_caps_word_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(KP_INST)
 
diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c
index 690ac971..0af30b00 100644
--- a/app/src/behaviors/behavior_ext_power.c
+++ b/app/src/behaviors/behavior_ext_power.c
@@ -74,7 +74,7 @@ static const struct behavior_driver_api behavior_ext_power_driver_api = {
     .locality = BEHAVIOR_LOCALITY_GLOBAL,
 };
 
-DEVICE_DT_INST_DEFINE(0, behavior_ext_power_init, NULL, NULL, NULL, APPLICATION,
-                      CONFIG_APPLICATION_INIT_PRIORITY, &behavior_ext_power_driver_api);
+BEHAVIOR_DT_INST_DEFINE(0, behavior_ext_power_init, NULL, NULL, NULL, APPLICATION,
+                        CONFIG_APPLICATION_INIT_PRIORITY, &behavior_ext_power_driver_api);
 
 #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c
index d4aa0dce..ea0448a4 100644
--- a/app/src/behaviors/behavior_hold_tap.c
+++ b/app/src/behaviors/behavior_hold_tap.c
@@ -511,7 +511,7 @@ static void update_hold_status_for_retro_tap(uint32_t ignore_position) {
 
 static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
                                        struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     const struct behavior_hold_tap_config *cfg = dev->config;
 
     if (undecided_hold_tap != NULL) {
@@ -703,8 +703,8 @@ static int behavior_hold_tap_init(const struct device *dev) {
 #define KP_INST(n)                                                                                 \
     static struct behavior_hold_tap_config behavior_hold_tap_config_##n = {                        \
         .tapping_term_ms = DT_INST_PROP(n, tapping_term_ms),                                       \
-        .hold_behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(n, bindings, 0), label),               \
-        .tap_behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(n, bindings, 1), label),                \
+        .hold_behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 0)),               \
+        .tap_behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 1)),                \
         .quick_tap_ms = DT_INST_PROP(n, quick_tap_ms),                                             \
         .require_prior_idle_ms = DT_INST_PROP(n, global_quick_tap)                                 \
                                      ? DT_INST_PROP(n, quick_tap_ms)                               \
@@ -715,9 +715,9 @@ static int behavior_hold_tap_init(const struct device *dev) {
         .hold_trigger_key_positions = DT_INST_PROP(n, hold_trigger_key_positions),                 \
         .hold_trigger_key_positions_len = DT_INST_PROP_LEN(n, hold_trigger_key_positions),         \
     };                                                                                             \
-    DEVICE_DT_INST_DEFINE(n, behavior_hold_tap_init, NULL, NULL, &behavior_hold_tap_config_##n,    \
-                          APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                        \
-                          &behavior_hold_tap_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_hold_tap_init, NULL, NULL, &behavior_hold_tap_config_##n,  \
+                            APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                      \
+                            &behavior_hold_tap_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(KP_INST)
 
diff --git a/app/src/behaviors/behavior_key_press.c b/app/src/behaviors/behavior_key_press.c
index 2765db9f..5549b4b4 100644
--- a/app/src/behaviors/behavior_key_press.c
+++ b/app/src/behaviors/behavior_key_press.c
@@ -36,7 +36,7 @@ static const struct behavior_driver_api behavior_key_press_driver_api = {
     .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released};
 
 #define KP_INST(n)                                                                                 \
-    DEVICE_DT_INST_DEFINE(n, behavior_key_press_init, NULL, NULL, NULL, APPLICATION,               \
-                          CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_press_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_key_press_init, NULL, NULL, NULL, APPLICATION,             \
+                            CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_press_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(KP_INST)
diff --git a/app/src/behaviors/behavior_key_repeat.c b/app/src/behaviors/behavior_key_repeat.c
index 033f498b..85377f3f 100644
--- a/app/src/behaviors/behavior_key_repeat.c
+++ b/app/src/behaviors/behavior_key_repeat.c
@@ -32,7 +32,7 @@ struct behavior_key_repeat_data {
 
 static int on_key_repeat_binding_pressed(struct zmk_behavior_binding *binding,
                                          struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     struct behavior_key_repeat_data *data = dev->data;
 
     if (data->last_keycode_pressed.usage_page == 0) {
@@ -50,7 +50,7 @@ static int on_key_repeat_binding_pressed(struct zmk_behavior_binding *binding,
 
 static int on_key_repeat_binding_released(struct zmk_behavior_binding *binding,
                                           struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     struct behavior_key_repeat_data *data = dev->data;
 
     if (data->current_keycode_pressed.usage_page == 0) {
@@ -116,9 +116,9 @@ static int behavior_key_repeat_init(const struct device *dev) {
         .usage_pages = DT_INST_PROP(n, usage_pages),                                               \
         .usage_pages_count = DT_INST_PROP_LEN(n, usage_pages),                                     \
     };                                                                                             \
-    DEVICE_DT_INST_DEFINE(n, behavior_key_repeat_init, NULL, &behavior_key_repeat_data_##n,        \
-                          &behavior_key_repeat_config_##n, APPLICATION,                            \
-                          CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_repeat_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_key_repeat_init, NULL, &behavior_key_repeat_data_##n,      \
+                            &behavior_key_repeat_config_##n, APPLICATION,                          \
+                            CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_repeat_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(KR_INST)
 
diff --git a/app/src/behaviors/behavior_key_toggle.c b/app/src/behaviors/behavior_key_toggle.c
index cbbdd0d9..0ab1bd02 100644
--- a/app/src/behaviors/behavior_key_toggle.c
+++ b/app/src/behaviors/behavior_key_toggle.c
@@ -38,7 +38,7 @@ static const struct behavior_driver_api behavior_key_toggle_driver_api = {
 };
 
 #define KT_INST(n)                                                                                 \
-    DEVICE_DT_INST_DEFINE(n, behavior_key_toggle_init, NULL, NULL, NULL, APPLICATION,              \
-                          CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_toggle_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_key_toggle_init, NULL, NULL, NULL, APPLICATION,            \
+                            CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_toggle_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(KT_INST)
diff --git a/app/src/behaviors/behavior_macro.c b/app/src/behaviors/behavior_macro.c
index c4728453..1cb76dbd 100644
--- a/app/src/behaviors/behavior_macro.c
+++ b/app/src/behaviors/behavior_macro.c
@@ -44,18 +44,18 @@ struct behavior_macro_config {
     struct zmk_behavior_binding bindings[];
 };
 
-#define TAP_MODE DT_PROP(DT_INST(0, zmk_macro_control_mode_tap), label)
-#define PRESS_MODE DT_PROP(DT_INST(0, zmk_macro_control_mode_press), label)
-#define REL_MODE DT_PROP(DT_INST(0, zmk_macro_control_mode_release), label)
+#define TAP_MODE DEVICE_DT_NAME(DT_INST(0, zmk_macro_control_mode_tap))
+#define PRESS_MODE DEVICE_DT_NAME(DT_INST(0, zmk_macro_control_mode_press))
+#define REL_MODE DEVICE_DT_NAME(DT_INST(0, zmk_macro_control_mode_release))
 
-#define TAP_TIME DT_PROP(DT_INST(0, zmk_macro_control_tap_time), label)
-#define WAIT_TIME DT_PROP(DT_INST(0, zmk_macro_control_wait_time), label)
-#define WAIT_REL DT_PROP(DT_INST(0, zmk_macro_pause_for_release), label)
+#define TAP_TIME DEVICE_DT_NAME(DT_INST(0, zmk_macro_control_tap_time))
+#define WAIT_TIME DEVICE_DT_NAME(DT_INST(0, zmk_macro_control_wait_time))
+#define WAIT_REL DEVICE_DT_NAME(DT_INST(0, zmk_macro_pause_for_release))
 
-#define P1TO1 DT_PROP(DT_INST(0, zmk_macro_param_1to1), label)
-#define P1TO2 DT_PROP(DT_INST(0, zmk_macro_param_1to2), label)
-#define P2TO1 DT_PROP(DT_INST(0, zmk_macro_param_2to1), label)
-#define P2TO2 DT_PROP(DT_INST(0, zmk_macro_param_2to2), label)
+#define P1TO1 DEVICE_DT_NAME(DT_INST(0, zmk_macro_param_1to1))
+#define P1TO2 DEVICE_DT_NAME(DT_INST(0, zmk_macro_param_1to2))
+#define P2TO1 DEVICE_DT_NAME(DT_INST(0, zmk_macro_param_2to1))
+#define P2TO2 DEVICE_DT_NAME(DT_INST(0, zmk_macro_param_2to2))
 
 #define ZM_IS_NODE_MATCH(a, b) (strcmp(a, b) == 0)
 #define IS_TAP_MODE(dev) ZM_IS_NODE_MATCH(dev, TAP_MODE)
@@ -184,7 +184,7 @@ static void queue_macro(uint32_t position, const struct zmk_behavior_binding bin
 
 static int on_macro_binding_pressed(struct zmk_behavior_binding *binding,
                                     struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     const struct behavior_macro_config *cfg = dev->config;
     struct behavior_macro_state *state = dev->data;
     struct behavior_macro_trigger_state trigger_state = {.mode = MACRO_MODE_TAP,
@@ -200,7 +200,7 @@ static int on_macro_binding_pressed(struct zmk_behavior_binding *binding,
 
 static int on_macro_binding_released(struct zmk_behavior_binding *binding,
                                      struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     const struct behavior_macro_config *cfg = dev->config;
     struct behavior_macro_state *state = dev->data;
 
@@ -224,9 +224,9 @@ static const struct behavior_driver_api behavior_macro_driver_api = {
         .default_tap_ms = DT_PROP_OR(inst, tap_ms, CONFIG_ZMK_MACRO_DEFAULT_TAP_MS),               \
         .count = DT_PROP_LEN(inst, bindings),                                                      \
         .bindings = TRANSFORMED_BEHAVIORS(inst)};                                                  \
-    DEVICE_DT_DEFINE(inst, behavior_macro_init, NULL, &behavior_macro_state_##inst,                \
-                     &behavior_macro_config_##inst, APPLICATION,                                   \
-                     CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_macro_driver_api);
+    BEHAVIOR_DT_DEFINE(inst, behavior_macro_init, NULL, &behavior_macro_state_##inst,              \
+                       &behavior_macro_config_##inst, APPLICATION,                                 \
+                       CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_macro_driver_api);
 
 DT_FOREACH_STATUS_OKAY(zmk_behavior_macro, MACRO_INST)
 DT_FOREACH_STATUS_OKAY(zmk_behavior_macro_one_param, MACRO_INST)
diff --git a/app/src/behaviors/behavior_mod_morph.c b/app/src/behaviors/behavior_mod_morph.c
index d540abd9..176b0f69 100644
--- a/app/src/behaviors/behavior_mod_morph.c
+++ b/app/src/behaviors/behavior_mod_morph.c
@@ -36,7 +36,7 @@ struct behavior_mod_morph_data {
 
 static int on_mod_morph_binding_pressed(struct zmk_behavior_binding *binding,
                                         struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     const struct behavior_mod_morph_config *cfg = dev->config;
     struct behavior_mod_morph_data *data = dev->data;
 
@@ -56,7 +56,7 @@ static int on_mod_morph_binding_pressed(struct zmk_behavior_binding *binding,
 
 static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
                                          struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     struct behavior_mod_morph_data *data = dev->data;
 
     if (data->pressed_binding == NULL) {
@@ -81,7 +81,7 @@ static int behavior_mod_morph_init(const struct device *dev) { return 0; }
 
 #define _TRANSFORM_ENTRY(idx, node)                                                                \
     {                                                                                              \
-        .behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(node, bindings, idx), label),               \
+        .behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)),               \
         .param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0),       \
                               (DT_INST_PHA_BY_IDX(node, bindings, idx, param1))),                  \
         .param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0),       \
@@ -97,9 +97,9 @@ static int behavior_mod_morph_init(const struct device *dev) { return 0; }
                                    (DT_INST_PROP(n, mods) & ~DT_INST_PROP(n, keep_mods))),         \
     };                                                                                             \
     static struct behavior_mod_morph_data behavior_mod_morph_data_##n = {};                        \
-    DEVICE_DT_INST_DEFINE(n, behavior_mod_morph_init, NULL, &behavior_mod_morph_data_##n,          \
-                          &behavior_mod_morph_config_##n, APPLICATION,                             \
-                          CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mod_morph_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_mod_morph_init, NULL, &behavior_mod_morph_data_##n,        \
+                            &behavior_mod_morph_config_##n, APPLICATION,                           \
+                            CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mod_morph_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(KP_INST)
 
diff --git a/app/src/behaviors/behavior_momentary_layer.c b/app/src/behaviors/behavior_momentary_layer.c
index c2bd0ffc..94da6441 100644
--- a/app/src/behaviors/behavior_momentary_layer.c
+++ b/app/src/behaviors/behavior_momentary_layer.c
@@ -39,5 +39,5 @@ static const struct behavior_mo_config behavior_mo_config = {};
 
 static struct behavior_mo_data behavior_mo_data;
 
-DEVICE_DT_INST_DEFINE(0, behavior_mo_init, NULL, &behavior_mo_data, &behavior_mo_config,
-                      APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mo_driver_api);
+BEHAVIOR_DT_INST_DEFINE(0, behavior_mo_init, NULL, &behavior_mo_data, &behavior_mo_config,
+                        APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mo_driver_api);
diff --git a/app/src/behaviors/behavior_mouse_key_press.c b/app/src/behaviors/behavior_mouse_key_press.c
index 67181557..e79bb747 100644
--- a/app/src/behaviors/behavior_mouse_key_press.c
+++ b/app/src/behaviors/behavior_mouse_key_press.c
@@ -39,9 +39,9 @@ static const struct behavior_driver_api behavior_mouse_key_press_driver_api = {
     .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released};
 
 #define MKP_INST(n)                                                                                \
-    DEVICE_DT_INST_DEFINE(n, behavior_mouse_key_press_init, NULL, NULL, NULL, APPLICATION,         \
-                          CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                                     \
-                          &behavior_mouse_key_press_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_mouse_key_press_init, NULL, NULL, NULL, APPLICATION,       \
+                            CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                                   \
+                            &behavior_mouse_key_press_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(MKP_INST)
 
diff --git a/app/src/behaviors/behavior_none.c b/app/src/behaviors/behavior_none.c
index 613ecbad..57208f36 100644
--- a/app/src/behaviors/behavior_none.c
+++ b/app/src/behaviors/behavior_none.c
@@ -33,7 +33,7 @@ static const struct behavior_driver_api behavior_none_driver_api = {
     .binding_released = on_keymap_binding_released,
 };
 
-DEVICE_DT_INST_DEFINE(0, behavior_none_init, NULL, NULL, NULL, APPLICATION,
-                      CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_none_driver_api);
+BEHAVIOR_DT_INST_DEFINE(0, behavior_none_init, NULL, NULL, NULL, APPLICATION,
+                        CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_none_driver_api);
 
 #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
diff --git a/app/src/behaviors/behavior_outputs.c b/app/src/behaviors/behavior_outputs.c
index 6ae81a0f..1185aaab 100644
--- a/app/src/behaviors/behavior_outputs.c
+++ b/app/src/behaviors/behavior_outputs.c
@@ -42,7 +42,7 @@ static const struct behavior_driver_api behavior_outputs_driver_api = {
     .binding_pressed = on_keymap_binding_pressed,
 };
 
-DEVICE_DT_INST_DEFINE(0, behavior_out_init, NULL, NULL, NULL, APPLICATION,
-                      CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_outputs_driver_api);
+BEHAVIOR_DT_INST_DEFINE(0, behavior_out_init, NULL, NULL, NULL, APPLICATION,
+                        CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_outputs_driver_api);
 
 #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
diff --git a/app/src/behaviors/behavior_reset.c b/app/src/behaviors/behavior_reset.c
index 0b983c84..6a2731ec 100644
--- a/app/src/behaviors/behavior_reset.c
+++ b/app/src/behaviors/behavior_reset.c
@@ -25,7 +25,7 @@ static int behavior_reset_init(const struct device *dev) { return 0; };
 
 static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
                                      struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     const struct behavior_reset_config *cfg = dev->config;
 
     // TODO: Correct magic code for going into DFU?
@@ -43,9 +43,9 @@ static const struct behavior_driver_api behavior_reset_driver_api = {
 #define RST_INST(n)                                                                                \
     static const struct behavior_reset_config behavior_reset_config_##n = {                        \
         .type = DT_INST_PROP(n, type)};                                                            \
-    DEVICE_DT_INST_DEFINE(n, behavior_reset_init, NULL, NULL, &behavior_reset_config_##n,          \
-                          APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                        \
-                          &behavior_reset_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_reset_init, NULL, NULL, &behavior_reset_config_##n,        \
+                            APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                      \
+                            &behavior_reset_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(RST_INST)
 
diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c
index 0af07f81..7a478eb7 100644
--- a/app/src/behaviors/behavior_rgb_underglow.c
+++ b/app/src/behaviors/behavior_rgb_underglow.c
@@ -149,7 +149,7 @@ static const struct behavior_driver_api behavior_rgb_underglow_driver_api = {
     .locality = BEHAVIOR_LOCALITY_GLOBAL,
 };
 
-DEVICE_DT_INST_DEFINE(0, behavior_rgb_underglow_init, NULL, NULL, NULL, APPLICATION,
-                      CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_rgb_underglow_driver_api);
+BEHAVIOR_DT_INST_DEFINE(0, behavior_rgb_underglow_init, NULL, NULL, NULL, APPLICATION,
+                        CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_rgb_underglow_driver_api);
 
 #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
diff --git a/app/src/behaviors/behavior_sensor_rotate.c b/app/src/behaviors/behavior_sensor_rotate.c
index 822bc206..f77beca1 100644
--- a/app/src/behaviors/behavior_sensor_rotate.c
+++ b/app/src/behaviors/behavior_sensor_rotate.c
@@ -20,7 +20,7 @@ static int behavior_sensor_rotate_init(const struct device *dev) { return 0; };
 
 #define _TRANSFORM_ENTRY(idx, node)                                                                \
     {                                                                                              \
-        .behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(node, bindings, idx), label),               \
+        .behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)),               \
         .param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0),       \
                               (DT_INST_PHA_BY_IDX(node, bindings, idx, param1))),                  \
         .param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0),       \
@@ -35,9 +35,9 @@ static int behavior_sensor_rotate_init(const struct device *dev) { return 0; };
         .override_params = false,                                                                  \
     };                                                                                             \
     static struct behavior_sensor_rotate_data behavior_sensor_rotate_data_##n = {};                \
-    DEVICE_DT_INST_DEFINE(n, behavior_sensor_rotate_init, NULL, &behavior_sensor_rotate_data_##n,  \
-                          &behavior_sensor_rotate_config_##n, APPLICATION,                         \
-                          CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                                     \
-                          &behavior_sensor_rotate_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_sensor_rotate_init, NULL,                                  \
+                            &behavior_sensor_rotate_data_##n, &behavior_sensor_rotate_config_##n,  \
+                            APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                      \
+                            &behavior_sensor_rotate_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_INST)
diff --git a/app/src/behaviors/behavior_sensor_rotate_common.c b/app/src/behaviors/behavior_sensor_rotate_common.c
index 98b4aec1..94bf40c1 100644
--- a/app/src/behaviors/behavior_sensor_rotate_common.c
+++ b/app/src/behaviors/behavior_sensor_rotate_common.c
@@ -15,7 +15,7 @@ int zmk_behavior_sensor_rotate_common_accept_data(
     struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
     const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
     const struct zmk_sensor_channel_data *channel_data) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     struct behavior_sensor_rotate_data *data = dev->data;
 
     const struct sensor_value value = channel_data[0].value;
@@ -58,7 +58,7 @@ int zmk_behavior_sensor_rotate_common_accept_data(
 int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *binding,
                                               struct zmk_behavior_binding_event event,
                                               enum behavior_sensor_binding_process_mode mode) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     const struct behavior_sensor_rotate_config *cfg = dev->config;
     struct behavior_sensor_rotate_data *data = dev->data;
 
diff --git a/app/src/behaviors/behavior_sensor_rotate_var.c b/app/src/behaviors/behavior_sensor_rotate_var.c
index e6d20cab..0d3d22b2 100644
--- a/app/src/behaviors/behavior_sensor_rotate_var.c
+++ b/app/src/behaviors/behavior_sensor_rotate_var.c
@@ -20,13 +20,13 @@ static int behavior_sensor_rotate_var_init(const struct device *dev) { return 0;
 
 #define SENSOR_ROTATE_VAR_INST(n)                                                                  \
     static struct behavior_sensor_rotate_config behavior_sensor_rotate_var_config_##n = {          \
-        .cw_binding = {.behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(n, bindings, 0), label)},    \
-        .ccw_binding = {.behavior_dev = DT_PROP(DT_INST_PHANDLE_BY_IDX(n, bindings, 1), label)},   \
+        .cw_binding = {.behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 0))},    \
+        .ccw_binding = {.behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 1))},   \
         .tap_ms = DT_INST_PROP(n, tap_ms),                                                         \
         .override_params = true,                                                                   \
     };                                                                                             \
     static struct behavior_sensor_rotate_data behavior_sensor_rotate_var_data_##n = {};            \
-    DEVICE_DT_INST_DEFINE(                                                                         \
+    BEHAVIOR_DT_INST_DEFINE(                                                                       \
         n, behavior_sensor_rotate_var_init, NULL, &behavior_sensor_rotate_var_data_##n,            \
         &behavior_sensor_rotate_var_config_##n, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,  \
         &behavior_sensor_rotate_var_driver_api);
diff --git a/app/src/behaviors/behavior_sticky_key.c b/app/src/behaviors/behavior_sticky_key.c
index 6697b9b1..67f77286 100644
--- a/app/src/behaviors/behavior_sticky_key.c
+++ b/app/src/behaviors/behavior_sticky_key.c
@@ -24,6 +24,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
 
 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
 
+#define KEY_PRESS DEVICE_DT_NAME(DT_INST(0, zmk_behavior_key_press))
+
 #define ZMK_BHV_STICKY_KEY_MAX_HELD 10
 
 #define ZMK_BHV_STICKY_KEY_POSITION_FREE UINT32_MAX
@@ -129,7 +131,7 @@ static int stop_timer(struct active_sticky_key *sticky_key) {
 
 static int on_sticky_key_binding_pressed(struct zmk_behavior_binding *binding,
                                          struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     const struct behavior_sticky_key_config *cfg = dev->config;
     struct active_sticky_key *sticky_key;
     sticky_key = find_sticky_key(event.position);
@@ -202,7 +204,7 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) {
             continue;
         }
 
-        if (strcmp(sticky_key->config->behavior.behavior_dev, "KEY_PRESS") == 0 &&
+        if (strcmp(sticky_key->config->behavior.behavior_dev, KEY_PRESS) == 0 &&
             ZMK_HID_USAGE_ID(sticky_key->param1) == ev_copy.keycode &&
             ZMK_HID_USAGE_PAGE(sticky_key->param1) == ev_copy.usage_page &&
             SELECT_MODS(sticky_key->param1) == ev_copy.implicit_modifiers) {
@@ -293,9 +295,9 @@ static struct behavior_sticky_key_data behavior_sticky_key_data;
         .ignore_modifiers = DT_INST_PROP(n, ignore_modifiers),                                     \
         .quick_release = DT_INST_PROP(n, quick_release),                                           \
     };                                                                                             \
-    DEVICE_DT_INST_DEFINE(n, behavior_sticky_key_init, NULL, &behavior_sticky_key_data,            \
-                          &behavior_sticky_key_config_##n, APPLICATION,                            \
-                          CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sticky_key_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_sticky_key_init, NULL, &behavior_sticky_key_data,          \
+                            &behavior_sticky_key_config_##n, APPLICATION,                          \
+                            CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sticky_key_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(KP_INST)
 
diff --git a/app/src/behaviors/behavior_tap_dance.c b/app/src/behaviors/behavior_tap_dance.c
index fc685124..306d5ca7 100644
--- a/app/src/behaviors/behavior_tap_dance.c
+++ b/app/src/behaviors/behavior_tap_dance.c
@@ -125,7 +125,7 @@ static inline int release_tap_dance_behavior(struct active_tap_dance *tap_dance,
 
 static int on_tap_dance_binding_pressed(struct zmk_behavior_binding *binding,
                                         struct zmk_behavior_binding_event event) {
-    const struct device *dev = device_get_binding(binding->behavior_dev);
+    const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
     const struct behavior_tap_dance_config *cfg = dev->config;
     struct active_tap_dance *tap_dance;
     tap_dance = find_tap_dance(event.position);
@@ -250,9 +250,9 @@ static int behavior_tap_dance_init(const struct device *dev) {
         .tapping_term_ms = DT_INST_PROP(n, tapping_term_ms),                                       \
         .behaviors = behavior_tap_dance_config_##n##_bindings,                                     \
         .behavior_count = DT_INST_PROP_LEN(n, bindings)};                                          \
-    DEVICE_DT_INST_DEFINE(n, behavior_tap_dance_init, NULL, NULL, &behavior_tap_dance_config_##n,  \
-                          APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                        \
-                          &behavior_tap_dance_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_tap_dance_init, NULL, NULL,                                \
+                            &behavior_tap_dance_config_##n, APPLICATION,                           \
+                            CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_tap_dance_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(KP_INST)
 
diff --git a/app/src/behaviors/behavior_to_layer.c b/app/src/behaviors/behavior_to_layer.c
index c05b83ea..9a58bf60 100644
--- a/app/src/behaviors/behavior_to_layer.c
+++ b/app/src/behaviors/behavior_to_layer.c
@@ -37,7 +37,7 @@ static const struct behavior_driver_api behavior_to_driver_api = {
     .binding_released = to_keymap_binding_released,
 };
 
-DEVICE_DT_INST_DEFINE(0, behavior_to_init, NULL, NULL, NULL, APPLICATION,
-                      CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_to_driver_api);
+BEHAVIOR_DT_INST_DEFINE(0, behavior_to_init, NULL, NULL, NULL, APPLICATION,
+                        CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_to_driver_api);
 
 #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
diff --git a/app/src/behaviors/behavior_toggle_layer.c b/app/src/behaviors/behavior_toggle_layer.c
index 73a700ed..154cf9cd 100644
--- a/app/src/behaviors/behavior_toggle_layer.c
+++ b/app/src/behaviors/behavior_toggle_layer.c
@@ -43,7 +43,7 @@ static const struct behavior_tog_config behavior_tog_config = {};
 
 static struct behavior_tog_data behavior_tog_data;
 
-DEVICE_DT_INST_DEFINE(0, behavior_tog_init, NULL, &behavior_tog_data, &behavior_tog_config,
-                      APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_tog_driver_api);
+BEHAVIOR_DT_INST_DEFINE(0, behavior_tog_init, NULL, &behavior_tog_data, &behavior_tog_config,
+                        APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_tog_driver_api);
 
 #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
diff --git a/app/src/behaviors/behavior_transparent.c b/app/src/behaviors/behavior_transparent.c
index eeb2242d..ddf62ce0 100644
--- a/app/src/behaviors/behavior_transparent.c
+++ b/app/src/behaviors/behavior_transparent.c
@@ -33,7 +33,7 @@ static const struct behavior_driver_api behavior_transparent_driver_api = {
     .binding_released = on_keymap_binding_released,
 };
 
-DEVICE_DT_INST_DEFINE(0, behavior_transparent_init, NULL, NULL, NULL, APPLICATION,
-                      CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_transparent_driver_api);
+BEHAVIOR_DT_INST_DEFINE(0, behavior_transparent_init, NULL, NULL, NULL, APPLICATION,
+                        CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_transparent_driver_api);
 
 #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
diff --git a/app/src/ble.c b/app/src/ble.c
index 483bc9d7..a5f973a4 100644
--- a/app/src/ble.c
+++ b/app/src/ble.c
@@ -106,7 +106,9 @@ void set_profile_address(uint8_t index, const bt_addr_le_t *addr) {
     memcpy(&profiles[index].peer, addr, sizeof(bt_addr_le_t));
     sprintf(setting_name, "ble/profiles/%d", index);
     LOG_DBG("Setting profile addr for %s to %s", setting_name, addr_str);
+#if IS_ENABLED(CONFIG_SETTINGS)
     settings_save_one(setting_name, &profiles[index], sizeof(struct zmk_ble_profile));
+#endif
     k_work_submit(&raise_profile_changed_event_work);
 }
 
@@ -224,6 +226,15 @@ int zmk_ble_clear_bonds() {
 
 int zmk_ble_active_profile_index() { return active_profile; }
 
+int zmk_ble_profile_index(const bt_addr_le_t *addr) {
+    for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) {
+        if (bt_addr_le_cmp(addr, &profiles[i].peer) == 0) {
+            return i;
+        }
+    }
+    return -ENODEV;
+}
+
 #if IS_ENABLED(CONFIG_SETTINGS)
 static void ble_save_profile_work(struct k_work *work) {
     settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile));
@@ -271,6 +282,27 @@ int zmk_ble_prof_prev() {
                                ZMK_BLE_PROFILE_COUNT);
 };
 
+int zmk_ble_prof_disconnect(uint8_t index) {
+    if (index >= ZMK_BLE_PROFILE_COUNT)
+        return -ERANGE;
+
+    bt_addr_le_t *addr = &profiles[index].peer;
+    struct bt_conn *conn;
+    int result;
+
+    if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
+        return -ENODEV;
+    } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) {
+        return -ENODEV;
+    }
+
+    result = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
+    LOG_DBG("Disconnected from profile %d: %d", index, result);
+
+    bt_conn_unref(conn);
+    return result;
+}
+
 bt_addr_le_t *zmk_ble_active_profile_addr() { return &profiles[active_profile].peer; }
 
 char *zmk_ble_active_profile_name() { return profiles[active_profile].name; }
@@ -415,9 +447,11 @@ static void connected(struct bt_conn *conn, uint8_t err) {
 
     LOG_DBG("Connected %s", addr);
 
+#if !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ)
     if (bt_conn_set_security(conn, BT_SECURITY_L2)) {
         LOG_ERR("Failed to set security");
     }
+#endif // !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ)
 
     update_advertising();
 
@@ -521,13 +555,19 @@ static void auth_cancel(struct bt_conn *conn) {
     LOG_DBG("Pairing cancelled: %s", addr);
 }
 
+static bool pairing_allowed_for_current_profile(struct bt_conn *conn) {
+    return zmk_ble_active_profile_is_open() ||
+           (IS_ENABLED(CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE) &&
+            bt_addr_le_cmp(zmk_ble_active_profile_addr(), bt_conn_get_dst(conn)) == 0);
+}
+
 static enum bt_security_err auth_pairing_accept(struct bt_conn *conn,
                                                 const struct bt_conn_pairing_feat *const feat) {
     struct bt_conn_info info;
     bt_conn_get_info(conn, &info);
 
     LOG_DBG("role %d, open? %s", info.role, zmk_ble_active_profile_is_open() ? "yes" : "no");
-    if (info.role == BT_CONN_ROLE_PERIPHERAL && !zmk_ble_active_profile_is_open()) {
+    if (info.role == BT_CONN_ROLE_PERIPHERAL && !pairing_allowed_for_current_profile(conn)) {
         LOG_WRN("Rejecting pairing request to taken profile %d", active_profile);
         return BT_SECURITY_ERR_PAIR_NOT_ALLOWED;
     }
@@ -548,7 +588,7 @@ static void auth_pairing_complete(struct bt_conn *conn, bool bonded) {
         return;
     }
 
-    if (!zmk_ble_active_profile_is_open()) {
+    if (!pairing_allowed_for_current_profile(conn)) {
         LOG_ERR("Pairing completed but current profile is not open: %s", addr);
         bt_unpair(BT_ID_DEFAULT, dst);
         return;
@@ -666,9 +706,9 @@ static int zmk_ble_handle_key_user(struct zmk_keycode_state_changed *event) {
         return ZMK_EV_EVENT_BUBBLE;
     }
 
-    if (!event->state) {
-        LOG_DBG("Key released, ignoring");
-        return ZMK_EV_EVENT_BUBBLE;
+    if (event->state) {
+        LOG_DBG("Key press, ignoring");
+        return ZMK_EV_EVENT_HANDLED;
     }
 
     if (key == HID_USAGE_KEY_KEYBOARD_ESCAPE) {
@@ -698,7 +738,7 @@ static int zmk_ble_handle_key_user(struct zmk_keycode_state_changed *event) {
           zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYPAD_1_AND_END,
                                          HID_USAGE_KEY_KEYPAD_0_AND_INSERT, &val))) {
         LOG_DBG("Key not a number, ignoring");
-        return ZMK_EV_EVENT_BUBBLE;
+        return ZMK_EV_EVENT_HANDLED;
     }
 
     if (ring_buf_space_get(&passkey_entries) <= 0) {
diff --git a/app/src/display/widgets/layer_status.c b/app/src/display/widgets/layer_status.c
index c3ddd07c..73c2268e 100644
--- a/app/src/display/widgets/layer_status.c
+++ b/app/src/display/widgets/layer_status.c
@@ -45,7 +45,7 @@ static void layer_status_update_cb(struct layer_status_state state) {
 
 static struct layer_status_state layer_status_get_state(const zmk_event_t *eh) {
     uint8_t index = zmk_keymap_highest_layer_active();
-    return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_label(index)};
+    return (struct layer_status_state){.index = index, .label = zmk_keymap_layer_name(index)};
 }
 
 ZMK_DISPLAY_WIDGET_LISTENER(widget_layer_status, struct layer_status_state, layer_status_update_cb,
diff --git a/app/src/events/hid_indicators_changed.c b/app/src/events/hid_indicators_changed.c
new file mode 100644
index 00000000..ded36835
--- /dev/null
+++ b/app/src/events/hid_indicators_changed.c
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2022 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <zephyr/kernel.h>
+#include <zmk/events/hid_indicators_changed.h>
+
+ZMK_EVENT_IMPL(zmk_hid_indicators_changed);
diff --git a/app/src/ext_power_generic.c b/app/src/ext_power_generic.c
index e35714da..52896f19 100644
--- a/app/src/ext_power_generic.c
+++ b/app/src/ext_power_generic.c
@@ -39,7 +39,7 @@ static void ext_power_save_state_work(struct k_work *work) {
     const struct device *ext_power = DEVICE_DT_GET(DT_DRV_INST(0));
     struct ext_power_generic_data *data = ext_power->data;
 
-    snprintf(setting_path, 40, "ext_power/state/%s", DT_INST_PROP(0, label));
+    snprintf(setting_path, sizeof(setting_path), "ext_power/state/%s", ext_power->name);
     settings_save_one(setting_path, &data->status, sizeof(data->status));
 }
 
@@ -86,38 +86,38 @@ static int ext_power_generic_get(const struct device *dev) {
 }
 
 #if IS_ENABLED(CONFIG_SETTINGS)
+static int ext_power_settings_set_status(const struct device *dev, size_t len,
+                                         settings_read_cb read_cb, void *cb_arg) {
+    struct ext_power_generic_data *data = dev->data;
+
+    if (len != sizeof(data->status)) {
+        return -EINVAL;
+    }
+
+    int rc = read_cb(cb_arg, &data->status, sizeof(data->status));
+    if (rc >= 0) {
+        data->settings_init = true;
+
+        if (data->status) {
+            ext_power_generic_enable(dev);
+        } else {
+            ext_power_generic_disable(dev);
+        }
+
+        return 0;
+    }
+    return rc;
+}
+
 static int ext_power_settings_set(const char *name, size_t len, settings_read_cb read_cb,
                                   void *cb_arg) {
+    const struct device *ext_power = DEVICE_DT_GET(DT_DRV_INST(0));
+
     const char *next;
-    int rc;
-
-    if (settings_name_steq(name, DT_INST_PROP(0, label), &next) && !next) {
-        const struct device *ext_power = DEVICE_DT_GET(DT_DRV_INST(0));
-        struct ext_power_generic_data *data = ext_power->data;
-
-        if (len != sizeof(data->status)) {
-            return -EINVAL;
-        }
-
-        rc = read_cb(cb_arg, &data->status, sizeof(data->status));
-        if (rc >= 0) {
-            data->settings_init = true;
-
-            if (ext_power == NULL) {
-                LOG_ERR("Unable to retrieve ext_power device: %s", DT_INST_PROP(0, label));
-                return -EIO;
-            }
-
-            if (data->status) {
-                ext_power_generic_enable(ext_power);
-            } else {
-                ext_power_generic_disable(ext_power);
-            }
-
-            return 0;
-        }
-        return rc;
+    if (settings_name_steq(name, ext_power->name, &next) && !next) {
+        return ext_power_settings_set_status(ext_power, len, read_cb, cb_arg);
     }
+
     return -ENOENT;
 }
 
diff --git a/app/src/hid_indicators.c b/app/src/hid_indicators.c
new file mode 100644
index 00000000..50b2fbcc
--- /dev/null
+++ b/app/src/hid_indicators.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2022 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+#include <zmk/ble.h>
+#include <zmk/endpoints.h>
+#include <zmk/hid_indicators.h>
+#include <zmk/events/hid_indicators_changed.h>
+#include <zmk/events/endpoint_changed.h>
+#include <zmk/split/bluetooth/central.h>
+
+LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+
+static zmk_hid_indicators_t hid_indicators[ZMK_ENDPOINT_COUNT];
+
+zmk_hid_indicators_t zmk_hid_indicators_get_current_profile(void) {
+    return zmk_hid_indicators_get_profile(zmk_endpoints_selected());
+}
+
+zmk_hid_indicators_t zmk_hid_indicators_get_profile(struct zmk_endpoint_instance endpoint) {
+    const int profile = zmk_endpoint_instance_to_index(endpoint);
+    return hid_indicators[profile];
+}
+
+static void raise_led_changed_event(struct k_work *_work) {
+    const zmk_hid_indicators_t indicators = zmk_hid_indicators_get_current_profile();
+
+    ZMK_EVENT_RAISE(new_zmk_hid_indicators_changed(
+        (struct zmk_hid_indicators_changed){.indicators = indicators}));
+
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) && IS_ENABLED(CONFIG_ZMK_SPLIT_BLE)
+    zmk_split_bt_update_hid_indicator(indicators);
+#endif
+}
+
+static K_WORK_DEFINE(led_changed_work, raise_led_changed_event);
+
+void zmk_hid_indicators_set_profile(zmk_hid_indicators_t indicators,
+                                    struct zmk_endpoint_instance endpoint) {
+    int profile = zmk_endpoint_instance_to_index(endpoint);
+
+    // This write is not happening on the main thread. To prevent potential data races, every
+    // operation involving hid_indicators must be atomic. Currently, each function either reads
+    // or writes only one entry at a time, so it is safe to do these operations without a lock.
+    hid_indicators[profile] = indicators;
+
+    k_work_submit(&led_changed_work);
+}
+
+void zmk_hid_indicators_process_report(struct zmk_hid_led_report_body *report,
+                                       struct zmk_endpoint_instance endpoint) {
+    const zmk_hid_indicators_t indicators = (zmk_hid_indicators_t)report->leds;
+    zmk_hid_indicators_set_profile(indicators, endpoint);
+
+    LOG_DBG("Update HID indicators: endpoint=%d, indicators=%x", endpoint.transport, indicators);
+}
+
+static int profile_listener(const zmk_event_t *eh) {
+    raise_led_changed_event(NULL);
+    return 0;
+}
+
+static ZMK_LISTENER(profile_listener, profile_listener);
+static ZMK_SUBSCRIPTION(profile_listener, zmk_endpoint_changed);
diff --git a/app/src/hog.c b/app/src/hog.c
index 89a903cb..1baf00b5 100644
--- a/app/src/hog.c
+++ b/app/src/hog.c
@@ -15,8 +15,12 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
 #include <zephyr/bluetooth/gatt.h>
 
 #include <zmk/ble.h>
+#include <zmk/endpoints_types.h>
 #include <zmk/hog.h>
 #include <zmk/hid.h>
+#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+#include <zmk/hid_indicators.h>
+#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
 
 enum {
     HIDS_REMOTE_WAKE = BIT(0),
@@ -51,6 +55,15 @@ static struct hids_report input = {
     .type = HIDS_INPUT,
 };
 
+#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+
+static struct hids_report led_indicators = {
+    .id = ZMK_HID_REPORT_ID_LEDS,
+    .type = HIDS_OUTPUT,
+};
+
+#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+
 static struct hids_report consumer_input = {
     .id = ZMK_HID_REPORT_ID_CONSUMER,
     .type = HIDS_INPUT,
@@ -94,6 +107,34 @@ static ssize_t read_hids_input_report(struct bt_conn *conn, const struct bt_gatt
                              sizeof(struct zmk_hid_keyboard_report_body));
 }
 
+#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+static ssize_t write_hids_leds_report(struct bt_conn *conn, const struct bt_gatt_attr *attr,
+                                      const void *buf, uint16_t len, uint16_t offset,
+                                      uint8_t flags) {
+    if (offset != 0) {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
+    }
+    if (len != sizeof(struct zmk_hid_led_report_body)) {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
+    }
+
+    struct zmk_hid_led_report_body *report = (struct zmk_hid_led_report_body *)buf;
+    int profile = zmk_ble_profile_index(bt_conn_get_dst(conn));
+    if (profile < 0) {
+        return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
+    }
+
+    struct zmk_endpoint_instance endpoint = {.transport = ZMK_TRANSPORT_BLE,
+                                             .ble = {
+                                                 .profile_index = profile,
+                                             }};
+    zmk_hid_indicators_process_report(report, endpoint);
+
+    return len;
+}
+
+#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+
 static ssize_t read_hids_consumer_input_report(struct bt_conn *conn,
                                                const struct bt_gatt_attr *attr, void *buf,
                                                uint16_t len, uint16_t offset) {
@@ -152,6 +193,7 @@ BT_GATT_SERVICE_DEFINE(
     BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT),
     BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref,
                        NULL, &input),
+
     BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
                            BT_GATT_PERM_READ_ENCRYPT, read_hids_consumer_input_report, NULL, NULL),
     BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT),
@@ -166,6 +208,15 @@ BT_GATT_SERVICE_DEFINE(
                        NULL, &mouse_input),
 #endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
 
+#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+    BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT,
+                           BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
+                           BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, NULL,
+                           write_hids_leds_report, NULL),
+    BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref,
+                       NULL, &led_indicators),
+#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+
     BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, BT_GATT_CHRC_WRITE_WITHOUT_RESP,
                            BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point));
 
@@ -251,7 +302,7 @@ void send_consumer_report_callback(struct k_work *work) {
         }
 
         struct bt_gatt_notify_params notify_params = {
-            .attr = &hog_svc.attrs[10],
+            .attr = &hog_svc.attrs[9],
             .data = &report,
             .len = sizeof(report),
         };
diff --git a/app/src/keymap.c b/app/src/keymap.c
index bda69427..d275feaf 100644
--- a/app/src/keymap.c
+++ b/app/src/keymap.c
@@ -31,15 +31,13 @@ static uint8_t _zmk_keymap_layer_default = 0;
 
 #define DT_DRV_COMPAT zmk_keymap
 
-#define BINDING_WITH_COMMA(idx, drv_inst) ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst)
-
 #define TRANSFORMED_LAYER(node)                                                                    \
-    {LISTIFY(DT_PROP_LEN(node, bindings), BINDING_WITH_COMMA, (, ), node)},
+    { LISTIFY(DT_PROP_LEN(node, bindings), ZMK_KEYMAP_EXTRACT_BINDING, (, ), node) }
 
 #if ZMK_KEYMAP_HAS_SENSORS
 #define _TRANSFORM_SENSOR_ENTRY(idx, layer)                                                        \
     {                                                                                              \
-        .behavior_dev = DT_PROP(DT_PHANDLE_BY_IDX(layer, sensor_bindings, idx), label),            \
+        .behavior_dev = DEVICE_DT_NAME(DT_PHANDLE_BY_IDX(layer, sensor_bindings, idx)),            \
         .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param1), (0),    \
                               (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param1))),               \
         .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param2), (0),    \
@@ -50,12 +48,11 @@ static uint8_t _zmk_keymap_layer_default = 0;
     COND_CODE_1(                                                                                   \
         DT_NODE_HAS_PROP(node, sensor_bindings),                                                   \
         ({LISTIFY(DT_PROP_LEN(node, sensor_bindings), _TRANSFORM_SENSOR_ENTRY, (, ), node)}),      \
-        ({})),
+        ({}))
 
 #endif /* ZMK_KEYMAP_HAS_SENSORS */
 
-#define LAYER_LABEL(node)                                                                          \
-    COND_CODE_0(DT_NODE_HAS_PROP(node, label), (NULL), (DT_PROP(node, label))),
+#define LAYER_NAME(node) DT_PROP_OR(node, display_name, DT_PROP_OR(node, label, NULL))
 
 // State
 
@@ -65,16 +62,16 @@ static uint8_t _zmk_keymap_layer_default = 0;
 static uint32_t zmk_keymap_active_behavior_layer[ZMK_KEYMAP_LEN];
 
 static struct zmk_behavior_binding zmk_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = {
-    DT_INST_FOREACH_CHILD(0, TRANSFORMED_LAYER)};
+    DT_INST_FOREACH_CHILD_SEP(0, TRANSFORMED_LAYER, (, ))};
 
 static const char *zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN] = {
-    DT_INST_FOREACH_CHILD(0, LAYER_LABEL)};
+    DT_INST_FOREACH_CHILD_SEP(0, LAYER_NAME, (, ))};
 
 #if ZMK_KEYMAP_HAS_SENSORS
 
-static struct zmk_behavior_binding zmk_sensor_keymap[ZMK_KEYMAP_LAYERS_LEN]
-                                                    [ZMK_KEYMAP_SENSORS_LEN] = {
-                                                        DT_INST_FOREACH_CHILD(0, SENSOR_LAYER)};
+static struct zmk_behavior_binding
+    zmk_sensor_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_SENSORS_LEN] = {
+        DT_INST_FOREACH_CHILD_SEP(0, SENSOR_LAYER, (, ))};
 
 #endif /* ZMK_KEYMAP_HAS_SENSORS */
 
@@ -148,7 +145,7 @@ bool is_active_layer(uint8_t layer, zmk_keymap_layers_state_t layer_state) {
     return (layer_state & BIT(layer)) == BIT(layer) || layer == _zmk_keymap_layer_default;
 }
 
-const char *zmk_keymap_layer_label(uint8_t layer) {
+const char *zmk_keymap_layer_name(uint8_t layer) {
     if (layer >= ZMK_KEYMAP_LAYERS_LEN) {
         return NULL;
     }
@@ -179,7 +176,7 @@ int zmk_keymap_apply_position_state(uint8_t source, int layer, uint32_t position
 
     LOG_DBG("layer: %d position: %d, binding name: %s", layer, position, binding.behavior_dev);
 
-    behavior = device_get_binding(binding.behavior_dev);
+    behavior = zmk_behavior_get_binding(binding.behavior_dev);
 
     if (!behavior) {
         LOG_WRN("No behavior assigned to %d on layer %d", position, layer);
@@ -259,7 +256,7 @@ int zmk_keymap_sensor_event(uint8_t sensor_index,
         LOG_DBG("layer: %d sensor_index: %d, binding name: %s", layer, sensor_index,
                 binding->behavior_dev);
 
-        const struct device *behavior = device_get_binding(binding->behavior_dev);
+        const struct device *behavior = zmk_behavior_get_binding(binding->behavior_dev);
         if (!behavior) {
             LOG_DBG("No behavior assigned to %d on layer %d", sensor_index, layer);
             continue;
diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c
index b80d4039..9d4f2cf1 100644
--- a/app/src/rgb_underglow.c
+++ b/app/src/rgb_underglow.c
@@ -67,7 +67,7 @@ static struct led_rgb pixels[STRIP_NUM_PIXELS];
 static struct rgb_underglow_state state;
 
 #if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
-static const struct device *ext_power;
+static const struct device *const ext_power = DEVICE_DT_GET(DT_INST(0, zmk_ext_power_generic));
 #endif
 
 static struct zmk_led_hsb hsb_scale_min_max(struct zmk_led_hsb hsb) {
@@ -243,9 +243,9 @@ static int zmk_rgb_underglow_init(const struct device *_arg) {
     led_strip = DEVICE_DT_GET(STRIP_CHOSEN);
 
 #if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
-    ext_power = device_get_binding("EXT_POWER");
-    if (ext_power == NULL) {
-        LOG_ERR("Unable to retrieve ext_power device: EXT_POWER");
+    if (!device_is_ready(ext_power)) {
+        LOG_ERR("External power device \"%s\" is not ready", ext_power->name);
+        return -ENODEV;
     }
 #endif
 
diff --git a/app/src/split/Kconfig b/app/src/split/Kconfig
index dbe5f092..11349370 100644
--- a/app/src/split/Kconfig
+++ b/app/src/split/Kconfig
@@ -20,6 +20,12 @@ config ZMK_SPLIT_BLE
 
 endchoice
 
+config ZMK_SPLIT_PERIPHERAL_HID_INDICATORS
+    bool "Peripheral HID Indicators"
+    depends on ZMK_HID_INDICATORS
+    help
+      Enable propogating the HID (LED) Indicator state to the split peripheral(s).
+
 #ZMK_SPLIT
 endif
 
diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c
index 860e89a5..36353224 100644
--- a/app/src/split/bluetooth/central.c
+++ b/app/src/split/bluetooth/central.c
@@ -27,6 +27,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
 #include <zmk/event_manager.h>
 #include <zmk/events/position_state_changed.h>
 #include <zmk/events/sensor_event.h>
+#include <zmk/hid_indicators_types.h>
 
 static int start_scanning(void);
 
@@ -46,6 +47,9 @@ struct peripheral_slot {
     struct bt_gatt_subscribe_params sensor_subscribe_params;
     struct bt_gatt_discover_params sub_discover_params;
     uint16_t run_behavior_handle;
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+    uint16_t update_hid_indicators;
+#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
     uint8_t position_state[POSITION_STATE_DATA_LEN];
     uint8_t changed_positions[POSITION_STATE_DATA_LEN];
 };
@@ -131,6 +135,9 @@ int release_peripheral_slot(int index) {
     // Clean up previously discovered handles;
     slot->subscribe_params.value_handle = 0;
     slot->run_behavior_handle = 0;
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+    slot->update_hid_indicators = 0;
+#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
 
     return 0;
 }
@@ -329,13 +336,23 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
         slot->discover_params.uuid = NULL;
         slot->discover_params.start_handle = attr->handle + 2;
         slot->run_behavior_handle = bt_gatt_attr_value_handle(attr);
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+    } else if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid,
+                            BT_UUID_DECLARE_128(ZMK_SPLIT_BT_UPDATE_HID_INDICATORS_UUID))) {
+        LOG_DBG("Found update HID indicators handle");
+        slot->update_hid_indicators = bt_gatt_attr_value_handle(attr);
+#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
     }
 
-    bool subscribed = slot->run_behavior_handle && slot->subscribe_params.value_handle;
+    bool subscribed = (slot->run_behavior_handle && slot->subscribe_params.value_handle);
 #if ZMK_KEYMAP_HAS_SENSORS
     subscribed = subscribed && slot->sensor_subscribe_params.value_handle;
 #endif /* ZMK_KEYMAP_HAS_SENSORS */
 
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+    subscribed = subscribed && slot->update_hid_indicators;
+#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+
     return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE;
 }
 
@@ -380,11 +397,13 @@ static void split_central_process_connection(struct bt_conn *conn) {
 
     LOG_DBG("Current security for connection: %d", bt_conn_get_security(conn));
 
+#if !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ)
     err = bt_conn_set_security(conn, BT_SECURITY_L2);
     if (err) {
         LOG_ERR("Failed to set security (reason %d)", err);
         return;
     }
+#endif // !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ)
 
     struct peripheral_slot *slot = peripheral_slot_for_conn(conn);
     if (slot == NULL) {
@@ -685,6 +704,43 @@ int zmk_split_bt_invoke_behavior(uint8_t source, struct zmk_behavior_binding *bi
     return split_bt_invoke_behavior_payload(wrapper);
 }
 
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+
+static zmk_hid_indicators_t hid_indicators = 0;
+
+static void split_central_update_indicators_callback(struct k_work *work) {
+    zmk_hid_indicators_t indicators = hid_indicators;
+    for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) {
+        if (peripherals[i].state != PERIPHERAL_SLOT_STATE_CONNECTED) {
+            continue;
+        }
+
+        if (peripherals[i].update_hid_indicators == 0) {
+            // It appears that sometimes the peripheral is considered connected
+            // before the GATT characteristics have been discovered. If this is
+            // the case, the update_hid_indicators handle will not yet be set.
+            continue;
+        }
+
+        int err = bt_gatt_write_without_response(peripherals[i].conn,
+                                                 peripherals[i].update_hid_indicators, &indicators,
+                                                 sizeof(indicators), true);
+
+        if (err) {
+            LOG_ERR("Failed to write HID indicator characteristic (err %d)", err);
+        }
+    }
+}
+
+static K_WORK_DEFINE(split_central_update_indicators, split_central_update_indicators_callback);
+
+int zmk_split_bt_update_hid_indicator(zmk_hid_indicators_t indicators) {
+    hid_indicators = indicators;
+    return k_work_submit_to_queue(&split_central_split_run_q, &split_central_update_indicators);
+}
+
+#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+
 int zmk_split_bt_central_init(const struct device *_arg) {
     k_work_queue_start(&split_central_split_run_q, split_central_split_run_q_stack,
                        K_THREAD_STACK_SIZEOF(split_central_split_run_q_stack),
diff --git a/app/src/split/bluetooth/peripheral.c b/app/src/split/bluetooth/peripheral.c
index 1d649f71..704e2eed 100644
--- a/app/src/split/bluetooth/peripheral.c
+++ b/app/src/split/bluetooth/peripheral.c
@@ -43,6 +43,8 @@ static const struct bt_data zmk_ble_ad[] = {
 
 static bool is_connected = false;
 
+static bool is_bonded = false;
+
 static void each_bond(const struct bt_bond_info *info, void *user_data) {
     bt_addr_le_t *addr = (bt_addr_le_t *)user_data;
 
@@ -57,10 +59,12 @@ static int start_advertising(bool low_duty) {
     bt_foreach_bond(BT_ID_DEFAULT, each_bond, &central_addr);
 
     if (bt_addr_le_cmp(&central_addr, BT_ADDR_LE_NONE) != 0) {
+        is_bonded = true;
         struct bt_le_adv_param adv_param = low_duty ? *BT_LE_ADV_CONN_DIR_LOW_DUTY(&central_addr)
                                                     : *BT_LE_ADV_CONN_DIR(&central_addr);
         return bt_le_adv_start(&adv_param, NULL, 0, NULL, 0);
     } else {
+        is_bonded = false;
         return bt_le_adv_start(BT_LE_ADV_CONN, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0);
     }
 };
@@ -132,8 +136,16 @@ static struct bt_conn_cb conn_callbacks = {
     .le_param_updated = le_param_updated,
 };
 
+static void auth_pairing_complete(struct bt_conn *conn, bool bonded) { is_bonded = bonded; }
+
+static struct bt_conn_auth_info_cb zmk_peripheral_ble_auth_info_cb = {
+    .pairing_complete = auth_pairing_complete,
+};
+
 bool zmk_split_bt_peripheral_is_connected() { return is_connected; }
 
+bool zmk_split_bt_peripheral_is_bonded() { return is_bonded; }
+
 static int zmk_peripheral_ble_init(const struct device *_arg) {
     int err = bt_enable(NULL);
 
@@ -155,6 +167,7 @@ static int zmk_peripheral_ble_init(const struct device *_arg) {
     bt_unpair(BT_ID_DEFAULT, NULL);
 #else
     bt_conn_cb_register(&conn_callbacks);
+    bt_conn_auth_info_cb_register(&zmk_peripheral_ble_auth_info_cb);
 
     low_duty_advertising = false;
     k_work_submit(&advertising_work);
diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c
index 620df53e..0072cf8c 100644
--- a/app/src/split/bluetooth/service.c
+++ b/app/src/split/bluetooth/service.c
@@ -21,6 +21,11 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
 #include <zmk/matrix.h>
 #include <zmk/split/bluetooth/uuid.h>
 #include <zmk/split/bluetooth/service.h>
+
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+#include <zmk/events/hid_indicators_changed.h>
+#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+
 #include <zmk/events/sensor_event.h>
 #include <zmk/sensors.h>
 
@@ -105,6 +110,34 @@ static void split_svc_pos_state_ccc(const struct bt_gatt_attr *attr, uint16_t va
     LOG_DBG("value %d", value);
 }
 
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+
+static zmk_hid_indicators_t hid_indicators = 0;
+
+static void split_svc_update_indicators_callback(struct k_work *work) {
+    LOG_DBG("Raising HID indicators changed event: %x", hid_indicators);
+    ZMK_EVENT_RAISE(new_zmk_hid_indicators_changed(
+        (struct zmk_hid_indicators_changed){.indicators = hid_indicators}));
+}
+
+static K_WORK_DEFINE(split_svc_update_indicators_work, split_svc_update_indicators_callback);
+
+static ssize_t split_svc_update_indicators(struct bt_conn *conn, const struct bt_gatt_attr *attr,
+                                           const void *buf, uint16_t len, uint16_t offset,
+                                           uint8_t flags) {
+    if (offset + len > sizeof(zmk_hid_indicators_t)) {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
+    }
+
+    memcpy((uint8_t *)&hid_indicators + offset, buf, len);
+
+    k_work_submit(&split_svc_update_indicators_work);
+
+    return len;
+}
+
+#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+
 BT_GATT_SERVICE_DEFINE(
     split_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID)),
     BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID),
@@ -122,6 +155,11 @@ BT_GATT_SERVICE_DEFINE(
                            split_svc_sensor_state, NULL, &last_sensor_event),
     BT_GATT_CCC(split_svc_sensor_state_ccc, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT),
 #endif /* ZMK_KEYMAP_HAS_SENSORS */
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
+    BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_UPDATE_HID_INDICATORS_UUID),
+                           BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE_ENCRYPT, NULL,
+                           split_svc_update_indicators, NULL),
+#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
 );
 
 K_THREAD_STACK_DEFINE(service_q_stack, CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE);
diff --git a/app/src/usb_hid.c b/app/src/usb_hid.c
index fd58c14b..34123140 100644
--- a/app/src/usb_hid.c
+++ b/app/src/usb_hid.c
@@ -13,6 +13,9 @@
 #include <zmk/usb.h>
 #include <zmk/hid.h>
 #include <zmk/keymap.h>
+#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+#include <zmk/hid_indicators.h>
+#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
 #include <zmk/event_manager.h>
 
 LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@@ -83,12 +86,44 @@ static int get_report_cb(const struct device *dev, struct usb_setup_packet *setu
     return 0;
 }
 
+static int set_report_cb(const struct device *dev, struct usb_setup_packet *setup, int32_t *len,
+                         uint8_t **data) {
+    if ((setup->wValue & HID_GET_REPORT_TYPE_MASK) != HID_REPORT_TYPE_OUTPUT) {
+        LOG_ERR("Unsupported report type %d requested",
+                (setup->wValue & HID_GET_REPORT_TYPE_MASK) >> 8);
+        return -ENOTSUP;
+    }
+
+    switch (setup->wValue & HID_GET_REPORT_ID_MASK) {
+#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+    case ZMK_HID_REPORT_ID_LEDS:
+        if (*len != sizeof(struct zmk_hid_led_report)) {
+            LOG_ERR("LED set report is malformed: length=%d", *len);
+            return -EINVAL;
+        } else {
+            struct zmk_hid_led_report *report = (struct zmk_hid_led_report *)*data;
+            struct zmk_endpoint_instance endpoint = {
+                .transport = ZMK_TRANSPORT_USB,
+            };
+            zmk_hid_indicators_process_report(&report->body, endpoint);
+        }
+        break;
+#endif // IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
+    default:
+        LOG_ERR("Invalid report ID %d requested", setup->wValue & HID_GET_REPORT_ID_MASK);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
 static const struct hid_ops ops = {
 #if IS_ENABLED(CONFIG_ZMK_USB_BOOT)
     .protocol_change = set_proto_cb,
 #endif
     .int_in_ready = in_ready_cb,
     .get_report = get_report_cb,
+    .set_report = set_report_cb,
 };
 
 static int zmk_usb_hid_send_report(const uint8_t *report, size_t len) {
diff --git a/app/tests/backlight/behavior_keymap.dtsi b/app/tests/backlight/behavior_keymap.dtsi
index 771072ac..4433f28c 100644
--- a/app/tests/backlight/behavior_keymap.dtsi
+++ b/app/tests/backlight/behavior_keymap.dtsi
@@ -12,17 +12,14 @@
         compatible = "gpio-leds";
         led_0 {
             gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
-            label = "Backlight LED 0";
         };
         led_1 {
             gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
-            label = "Backlight LED 1";
         };
     };
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/backlight/cycle/native_posix_64.keymap b/app/tests/backlight/cycle/native_posix_64.keymap
index 00615e35..dcc23aa5 100644
--- a/app/tests/backlight/cycle/native_posix_64.keymap
+++ b/app/tests/backlight/cycle/native_posix_64.keymap
@@ -12,17 +12,14 @@
         compatible = "gpio-leds";
         led_0 {
             gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
-            label = "Backlight LED 0";
         };
         led_1 {
             gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
-            label = "Backlight LED 1";
         };
     };
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/ble/central/CMakeLists.txt b/app/tests/ble/central/CMakeLists.txt
new file mode 100644
index 00000000..020bef38
--- /dev/null
+++ b/app/tests/ble/central/CMakeLists.txt
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.20.0)
+find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
+project(ble_test_central)
+
+FILE(GLOB app_sources src/*.c)
+target_sources(app PRIVATE ${app_sources})
+
+# zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)
diff --git a/app/tests/ble/central/prj.conf b/app/tests/ble/central/prj.conf
new file mode 100644
index 00000000..735d4ac5
--- /dev/null
+++ b/app/tests/ble/central/prj.conf
@@ -0,0 +1,9 @@
+CONFIG_BT=y
+CONFIG_LOG=y
+CONFIG_BOOT_BANNER=n
+CONFIG_BT_LOG_LEVEL_WRN=y
+CONFIG_LOG_BACKEND_SHOW_COLOR=n
+CONFIG_BT_CENTRAL=y
+CONFIG_BT_SMP=y
+CONFIG_BT_SCAN_WITH_IDENTITY=y
+CONFIG_BT_GATT_CLIENT=y
diff --git a/app/tests/ble/central/src/main.c b/app/tests/ble/central/src/main.c
new file mode 100644
index 00000000..67521e60
--- /dev/null
+++ b/app/tests/ble/central/src/main.c
@@ -0,0 +1,369 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2015-2016 Intel Corporation
+ * Copyright (c) 2023 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/types.h>
+#include <stddef.h>
+#include <errno.h>
+#include <zephyr/kernel.h>
+
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(ble_central, 4);
+
+#include <zephyr/bluetooth/bluetooth.h>
+#include <zephyr/bluetooth/hci.h>
+#include <zephyr/bluetooth/conn.h>
+#include <zephyr/bluetooth/uuid.h>
+#include <zephyr/bluetooth/gatt.h>
+#include <zephyr/sys/byteorder.h>
+
+#ifdef CONFIG_ARCH_POSIX
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cmdline.h"
+#include "soc.h"
+
+static bool disconnect_and_reconnect = false;
+static bool clear_bond_on_disconnect = false;
+static bool halt_after_bonding = false;
+static int32_t wait_on_start = 0;
+
+static void ble_central_native_posix_options(void) {
+    static struct args_struct_t options[] = {
+        {.is_switch = true,
+         .option = "disconnect_and_reconnect",
+         .type = 'b',
+         .dest = (void *)&disconnect_and_reconnect,
+         .descript = "Disconnect and reconnect after the initial connection"},
+        {.is_switch = true,
+         .option = "halt_after_bonding",
+         .type = 'b',
+         .dest = (void *)&halt_after_bonding,
+         .descript = "Halt any further logic after bonding the first time"},
+        {.is_switch = true,
+         .option = "clear_bond_on_disconnect",
+         .type = 'b',
+         .dest = (void *)&clear_bond_on_disconnect,
+         .descript = "Clear bonds on disconnect and reconnect"},
+        {.option = "wait_on_start",
+         .name = "milliseconds",
+         .type = 'u',
+         .dest = (void *)&wait_on_start,
+         .descript = "Time in milliseconds to wait before starting the test process"},
+        ARG_TABLE_ENDMARKER};
+
+    native_add_command_line_opts(options);
+}
+
+NATIVE_TASK(ble_central_native_posix_options, PRE_BOOT_1, 1);
+
+#endif
+
+static void start_scan(void);
+
+static struct bt_conn *default_conn;
+
+static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0);
+static struct bt_gatt_discover_params discover_params;
+static struct bt_gatt_subscribe_params subscribe_params;
+
+static uint8_t notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params,
+                           const void *data, uint16_t length) {
+    if (!data) {
+        LOG_DBG("[UNSUBSCRIBED]");
+        params->value_handle = 0U;
+        return BT_GATT_ITER_STOP;
+    }
+
+    LOG_HEXDUMP_DBG(data, length, "payload");
+
+    return BT_GATT_ITER_CONTINUE;
+}
+
+static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
+                             struct bt_gatt_discover_params *params) {
+    int err;
+
+    if (!attr) {
+        LOG_DBG("[Discover complete]");
+        (void)memset(params, 0, sizeof(*params));
+        return BT_GATT_ITER_STOP;
+    }
+
+    LOG_DBG("[ATTRIBUTE] handle %u", attr->handle);
+
+    if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HIDS)) {
+        memcpy(&uuid, BT_UUID_HIDS_REPORT, sizeof(uuid));
+        discover_params.uuid = &uuid.uuid;
+        discover_params.start_handle = attr->handle + 1;
+        discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
+
+        err = bt_gatt_discover(conn, &discover_params);
+        if (err) {
+            LOG_DBG("[Discover failed] (err %d)", err);
+        }
+    } else if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HIDS_REPORT)) {
+        memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
+        discover_params.uuid = &uuid.uuid;
+        discover_params.start_handle = attr->handle + 2;
+        discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
+        subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
+
+        err = bt_gatt_discover(conn, &discover_params);
+        if (err) {
+            LOG_DBG("[Discover failed] (err %d)", err);
+        }
+    } else {
+        subscribe_params.notify = notify_func;
+        subscribe_params.value = BT_GATT_CCC_NOTIFY;
+        subscribe_params.ccc_handle = attr->handle;
+
+        err = bt_gatt_subscribe(conn, &subscribe_params);
+        if (err && err != -EALREADY) {
+            LOG_DBG("[Subscribe failed] (err %d)", err);
+        } else {
+            LOG_DBG("[SUBSCRIBED]");
+        }
+
+        return BT_GATT_ITER_STOP;
+    }
+
+    return BT_GATT_ITER_STOP;
+}
+
+static void reconnect(const bt_addr_le_t *addr) {
+    struct bt_le_conn_param *param;
+    int err = bt_le_scan_stop();
+    if (err < 0) {
+        LOG_DBG("Stop LE scan failed (err %d)", err);
+    }
+
+    param = BT_LE_CONN_PARAM_DEFAULT;
+    err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn);
+    if (err < 0) {
+        LOG_DBG("Create conn failed (err %d)", err);
+        start_scan();
+    }
+}
+
+static bool eir_found(struct bt_data *data, void *user_data) {
+    bt_addr_le_t *addr = user_data;
+    int i;
+
+    LOG_DBG("[AD]: %u data_len %u", data->type, data->data_len);
+
+    switch (data->type) {
+    case BT_DATA_UUID16_SOME:
+    case BT_DATA_UUID16_ALL:
+        if (data->data_len % sizeof(uint16_t) != 0U) {
+            LOG_DBG("[AD malformed]");
+            return true;
+        }
+
+        for (i = 0; i < data->data_len; i += sizeof(uint16_t)) {
+            struct bt_le_conn_param *param;
+            struct bt_uuid *uuid;
+            uint16_t u16;
+            int err;
+
+            memcpy(&u16, &data->data[i], sizeof(u16));
+            uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16));
+            if (bt_uuid_cmp(uuid, BT_UUID_HIDS)) {
+                continue;
+            }
+
+            err = bt_le_scan_stop();
+            if (err) {
+                LOG_DBG("[Stop LE scan failed] (err %d)", err);
+                continue;
+            }
+
+            param = BT_LE_CONN_PARAM_DEFAULT;
+            err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn);
+            if (err) {
+                LOG_DBG("[Create conn failed] (err %d)", err);
+                start_scan();
+            }
+
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
+                         struct net_buf_simple *ad) {
+    char dev[BT_ADDR_LE_STR_LEN];
+
+    bt_addr_le_to_str(addr, dev, sizeof(dev));
+    LOG_DBG("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i", dev, type, ad->len, rssi);
+
+    /* We're only interested in connectable events */
+    if (type == BT_GAP_ADV_TYPE_ADV_IND) {
+        bt_data_parse(ad, eir_found, (void *)addr);
+    } else if (type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
+        reconnect(addr);
+    }
+}
+
+static void start_scan(void) {
+    int err;
+
+    /* Use active scanning and disable duplicate filtering to handle any
+     * devices that might update their advertising data at runtime. */
+    struct bt_le_scan_param scan_param = {
+        .type = BT_LE_SCAN_TYPE_ACTIVE,
+        .options = BT_LE_SCAN_OPT_NONE,
+        .interval = BT_GAP_SCAN_FAST_INTERVAL,
+        .window = BT_GAP_SCAN_FAST_WINDOW,
+    };
+
+    err = bt_le_scan_start(&scan_param, device_found);
+    if (err) {
+        LOG_DBG("[Scanning failed to start] (err %d)", err);
+        return;
+    }
+
+    LOG_DBG("[Scanning successfully started]");
+}
+
+static void discover_conn(struct bt_conn *conn) {
+    int err;
+
+    LOG_DBG("[Discovery started for conn]");
+    memcpy(&uuid, BT_UUID_HIDS, sizeof(uuid));
+    discover_params.uuid = &uuid.uuid;
+    discover_params.func = discover_func;
+    discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
+    discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
+    discover_params.type = BT_GATT_DISCOVER_PRIMARY;
+
+    err = bt_gatt_discover(default_conn, &discover_params);
+    if (err) {
+        LOG_DBG("[Discover failed] (err %d)", err);
+        return;
+    }
+}
+
+static void connected(struct bt_conn *conn, uint8_t conn_err) {
+    char addr[BT_ADDR_LE_STR_LEN];
+
+    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+    if (conn_err) {
+        LOG_DBG("[Failed to connect to %s] (%u)", addr, conn_err);
+
+        bt_conn_unref(default_conn);
+        default_conn = NULL;
+
+        start_scan();
+        return;
+    }
+
+    LOG_DBG("[Connected]: %s", addr);
+
+    if (conn == default_conn) {
+        if (bt_conn_get_security(conn) >= BT_SECURITY_L2) {
+            discover_conn(conn);
+        } else {
+            LOG_DBG("[Setting the security for the connection]");
+            bt_conn_set_security(conn, BT_SECURITY_L2);
+        }
+    }
+}
+
+static bool first_connect = true;
+static void pairing_complete(struct bt_conn *conn, bool bonded) { LOG_DBG("Pairing complete"); }
+
+static void do_disconnect_of_active(struct k_work *work) {
+    bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
+    if (clear_bond_on_disconnect) {
+        bt_unpair(BT_ID_DEFAULT, bt_conn_get_dst(default_conn));
+    }
+}
+
+static K_WORK_DELAYABLE_DEFINE(disconnect_work, do_disconnect_of_active);
+
+static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) {
+    if (err > BT_SECURITY_ERR_SUCCESS) {
+        LOG_DBG("[Security Change Failed]");
+        exit(1);
+    }
+
+    if (halt_after_bonding) {
+        exit(1);
+    }
+
+    bool do_disconnect = first_connect && disconnect_and_reconnect;
+    first_connect = false;
+    if (do_disconnect) {
+        k_work_reschedule(&disconnect_work, K_MSEC(500));
+    } else {
+        discover_conn(conn);
+    }
+}
+
+static void disconnected(struct bt_conn *conn, uint8_t reason) {
+    char addr[BT_ADDR_LE_STR_LEN];
+
+    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+    LOG_DBG("[Disconnected]: %s (reason 0x%02x)", addr, reason);
+
+    if (default_conn != conn) {
+        return;
+    }
+
+    bt_conn_unref(default_conn);
+    default_conn = NULL;
+
+    if (!halt_after_bonding) {
+        start_scan();
+    }
+}
+
+BT_CONN_CB_DEFINE(conn_callbacks) = {
+    .connected = connected,
+    .disconnected = disconnected,
+    .security_changed = security_changed,
+};
+
+struct bt_conn_auth_info_cb auth_info_cb = {
+    .pairing_complete = pairing_complete,
+};
+
+void main(void) {
+    int err;
+
+    if (wait_on_start > 0) {
+        k_sleep(K_MSEC(wait_on_start));
+    }
+
+    err = bt_conn_auth_info_cb_register(&auth_info_cb);
+
+    err = bt_enable(NULL);
+
+    if (err) {
+        LOG_DBG("[Bluetooth init failed] (err %d)", err);
+        return;
+    }
+
+    LOG_DBG("[Bluetooth initialized]");
+
+    start_scan();
+}
diff --git a/app/tests/ble/profiles/bond-clear-then-bond-second-client/centrals.txt b/app/tests/ble/profiles/bond-clear-then-bond-second-client/centrals.txt
new file mode 100644
index 00000000..80601bad
--- /dev/null
+++ b/app/tests/ble/profiles/bond-clear-then-bond-second-client/centrals.txt
@@ -0,0 +1,2 @@
+./ble_test_central.exe -d=2 -halt_after_bonding
+./ble_test_central.exe -d=3 -wait_on_start=1300
diff --git a/app/tests/ble/profiles/bond-clear-then-bond-second-client/events.patterns b/app/tests/ble/profiles/bond-clear-then-bond-second-client/events.patterns
new file mode 100644
index 00000000..dbfe5627
--- /dev/null
+++ b/app/tests/ble/profiles/bond-clear-then-bond-second-client/events.patterns
@@ -0,0 +1,2 @@
+s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9]  .{19}/profile 0 /p
+s/^d_03: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9]  .{19}/profile 1 /p
diff --git a/app/tests/ble/profiles/bond-clear-then-bond-second-client/nrf52_bsim.keymap b/app/tests/ble/profiles/bond-clear-then-bond-second-client/nrf52_bsim.keymap
new file mode 100644
index 00000000..36eba046
--- /dev/null
+++ b/app/tests/ble/profiles/bond-clear-then-bond-second-client/nrf52_bsim.keymap
@@ -0,0 +1,24 @@
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/kscan_mock.h>
+
+&kscan {
+    events =
+    <ZMK_MOCK_PRESS(1,1,5000)
+    ZMK_MOCK_RELEASE(1,1,200)
+    ZMK_MOCK_PRESS(0,0,10)
+    ZMK_MOCK_RELEASE(0,0,2000)>;
+};
+
+/ {
+    keymap {
+        compatible = "zmk,keymap";
+
+        default_layer {
+            bindings = <
+            &kp A &kp B
+            &bt BT_SEL 0 &bt BT_CLR>;
+        };
+    };
+};
diff --git a/app/tests/ble/profiles/bond-clear-then-bond-second-client/snapshot.log b/app/tests/ble/profiles/bond-clear-then-bond-second-client/snapshot.log
new file mode 100644
index 00000000..4939c0d7
--- /dev/null
+++ b/app/tests/ble/profiles/bond-clear-then-bond-second-client/snapshot.log
@@ -0,0 +1,33 @@
+profile 0 <wrn> bt_id: No static addresses stored in controller
+profile 0 <dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
+profile 0 <dbg> ble_central: start_scan: [Scanning successfully started]
+profile 0 <dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+profile 0 <dbg> ble_central: eir_found: [AD]: 9 data_len 0
+profile 0 <dbg> ble_central: eir_found: [AD]: 25 data_len 2
+profile 0 <dbg> ble_central: eir_found: [AD]: 1 data_len 1
+profile 0 <dbg> ble_central: eir_found: [AD]: 2 data_len 4
+profile 0 <dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+profile 0 <dbg> ble_central: connected: [Setting the security for the connection]
+profile 0 <dbg> ble_central: pairing_complete: Pairing complete
+profile 1 <wrn> bt_id: No static addresses stored in controller
+profile 1 <dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
+profile 1 <dbg> ble_central: start_scan: [Scanning successfully started]
+profile 1 <dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+profile 1 <dbg> ble_central: eir_found: [AD]: 9 data_len 0
+profile 1 <dbg> ble_central: eir_found: [AD]: 25 data_len 2
+profile 1 <dbg> ble_central: eir_found: [AD]: 1 data_len 1
+profile 1 <dbg> ble_central: eir_found: [AD]: 2 data_len 4
+profile 1 <dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+profile 1 <dbg> ble_central: connected: [Setting the security for the connection]
+profile 1 <dbg> ble_central: pairing_complete: Pairing complete
+profile 1 <dbg> ble_central: discover_conn: [Discovery started for conn]
+profile 1 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 23
+profile 1 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 28
+profile 1 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 30
+profile 1 <dbg> ble_central: discover_func: [SUBSCRIBED]
+profile 1 <dbg> ble_central: notify_func: payload
+profile 1                    00 00 04 00 00 00 00 00                          |........
+profile 1 <dbg> ble_central: notify_func: payload
+profile 1                    00 00 00 00 00 00 00 00                          |........
+profile 1 <dbg> ble_central: notify_func: payload
+profile 1                    00 00 00 00 00 00 00 00                          |........
diff --git a/app/tests/ble/profiles/bond-to-cleared-profile/centrals.txt b/app/tests/ble/profiles/bond-to-cleared-profile/centrals.txt
new file mode 100644
index 00000000..80601bad
--- /dev/null
+++ b/app/tests/ble/profiles/bond-to-cleared-profile/centrals.txt
@@ -0,0 +1,2 @@
+./ble_test_central.exe -d=2 -halt_after_bonding
+./ble_test_central.exe -d=3 -wait_on_start=1300
diff --git a/app/tests/ble/profiles/bond-to-cleared-profile/events.patterns b/app/tests/ble/profiles/bond-to-cleared-profile/events.patterns
new file mode 100644
index 00000000..dbfe5627
--- /dev/null
+++ b/app/tests/ble/profiles/bond-to-cleared-profile/events.patterns
@@ -0,0 +1,2 @@
+s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9]  .{19}/profile 0 /p
+s/^d_03: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9]  .{19}/profile 1 /p
diff --git a/app/tests/ble/profiles/bond-to-cleared-profile/nrf52_bsim.keymap b/app/tests/ble/profiles/bond-to-cleared-profile/nrf52_bsim.keymap
new file mode 100644
index 00000000..45e2aea0
--- /dev/null
+++ b/app/tests/ble/profiles/bond-to-cleared-profile/nrf52_bsim.keymap
@@ -0,0 +1,24 @@
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/kscan_mock.h>
+
+&kscan {
+    events =
+    <ZMK_MOCK_PRESS(1,1,1000)
+    ZMK_MOCK_RELEASE(1,1,2000)
+    ZMK_MOCK_PRESS(0,0,100)
+    ZMK_MOCK_RELEASE(0,0,1000)>;
+};
+
+/ {
+    keymap {
+        compatible = "zmk,keymap";
+
+        default_layer {
+            bindings = <
+            &kp A &kp B
+            &bt BT_SEL 0 &bt BT_CLR>;
+        };
+    };
+};
diff --git a/app/tests/ble/profiles/bond-to-cleared-profile/snapshot.log b/app/tests/ble/profiles/bond-to-cleared-profile/snapshot.log
new file mode 100644
index 00000000..4939c0d7
--- /dev/null
+++ b/app/tests/ble/profiles/bond-to-cleared-profile/snapshot.log
@@ -0,0 +1,33 @@
+profile 0 <wrn> bt_id: No static addresses stored in controller
+profile 0 <dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
+profile 0 <dbg> ble_central: start_scan: [Scanning successfully started]
+profile 0 <dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+profile 0 <dbg> ble_central: eir_found: [AD]: 9 data_len 0
+profile 0 <dbg> ble_central: eir_found: [AD]: 25 data_len 2
+profile 0 <dbg> ble_central: eir_found: [AD]: 1 data_len 1
+profile 0 <dbg> ble_central: eir_found: [AD]: 2 data_len 4
+profile 0 <dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+profile 0 <dbg> ble_central: connected: [Setting the security for the connection]
+profile 0 <dbg> ble_central: pairing_complete: Pairing complete
+profile 1 <wrn> bt_id: No static addresses stored in controller
+profile 1 <dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
+profile 1 <dbg> ble_central: start_scan: [Scanning successfully started]
+profile 1 <dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+profile 1 <dbg> ble_central: eir_found: [AD]: 9 data_len 0
+profile 1 <dbg> ble_central: eir_found: [AD]: 25 data_len 2
+profile 1 <dbg> ble_central: eir_found: [AD]: 1 data_len 1
+profile 1 <dbg> ble_central: eir_found: [AD]: 2 data_len 4
+profile 1 <dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+profile 1 <dbg> ble_central: connected: [Setting the security for the connection]
+profile 1 <dbg> ble_central: pairing_complete: Pairing complete
+profile 1 <dbg> ble_central: discover_conn: [Discovery started for conn]
+profile 1 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 23
+profile 1 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 28
+profile 1 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 30
+profile 1 <dbg> ble_central: discover_func: [SUBSCRIBED]
+profile 1 <dbg> ble_central: notify_func: payload
+profile 1                    00 00 04 00 00 00 00 00                          |........
+profile 1 <dbg> ble_central: notify_func: payload
+profile 1                    00 00 00 00 00 00 00 00                          |........
+profile 1 <dbg> ble_central: notify_func: payload
+profile 1                    00 00 00 00 00 00 00 00                          |........
diff --git a/app/tests/ble/profiles/connnect-and-output-to-selection/centrals.txt b/app/tests/ble/profiles/connnect-and-output-to-selection/centrals.txt
new file mode 100644
index 00000000..110e617d
--- /dev/null
+++ b/app/tests/ble/profiles/connnect-and-output-to-selection/centrals.txt
@@ -0,0 +1 @@
+./ble_test_central.exe -d=2
diff --git a/app/tests/ble/profiles/connnect-and-output-to-selection/events.patterns b/app/tests/ble/profiles/connnect-and-output-to-selection/events.patterns
new file mode 100644
index 00000000..cca5a2d4
--- /dev/null
+++ b/app/tests/ble/profiles/connnect-and-output-to-selection/events.patterns
@@ -0,0 +1 @@
+s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9]  .{19}//p
diff --git a/app/tests/ble/profiles/connnect-and-output-to-selection/nrf52_bsim.keymap b/app/tests/ble/profiles/connnect-and-output-to-selection/nrf52_bsim.keymap
new file mode 100644
index 00000000..7c67425e
--- /dev/null
+++ b/app/tests/ble/profiles/connnect-and-output-to-selection/nrf52_bsim.keymap
@@ -0,0 +1,24 @@
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/kscan_mock.h>
+
+&kscan {
+    events =
+    <ZMK_MOCK_PRESS(0,0,10000)
+    ZMK_MOCK_RELEASE(0,0,2000)
+    ZMK_MOCK_PRESS(0,1,100)
+    ZMK_MOCK_RELEASE(0,1,1000)>;
+};
+
+/ {
+    keymap {
+        compatible = "zmk,keymap";
+
+        default_layer {
+            bindings = <
+            &kp A &kp B
+            &bt BT_SEL 0 &bt BT_SEL 1>;
+        };
+    };
+};
diff --git a/app/tests/ble/profiles/connnect-and-output-to-selection/snapshot.log b/app/tests/ble/profiles/connnect-and-output-to-selection/snapshot.log
new file mode 100644
index 00000000..092bb034
--- /dev/null
+++ b/app/tests/ble/profiles/connnect-and-output-to-selection/snapshot.log
@@ -0,0 +1,26 @@
+<wrn> bt_id: No static addresses stored in controller
+<dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
+<dbg> ble_central: start_scan: [Scanning successfully started]
+<dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+<dbg> ble_central: eir_found: [AD]: 9 data_len 0
+<dbg> ble_central: eir_found: [AD]: 25 data_len 2
+<dbg> ble_central: eir_found: [AD]: 1 data_len 1
+<dbg> ble_central: eir_found: [AD]: 2 data_len 4
+<dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+<dbg> ble_central: connected: [Setting the security for the connection]
+<dbg> ble_central: pairing_complete: Pairing complete
+<dbg> ble_central: discover_conn: [Discovery started for conn]
+<dbg> ble_central: discover_func: [ATTRIBUTE] handle 23
+<dbg> ble_central: discover_func: [ATTRIBUTE] handle 28
+<dbg> ble_central: discover_func: [ATTRIBUTE] handle 30
+<dbg> ble_central: discover_func: [SUBSCRIBED]
+<dbg> ble_central: notify_func: payload
+                   00 00 04 00 00 00 00 00                          |........
+<dbg> ble_central: notify_func: payload
+                   00 00 00 00 00 00 00 00                          |........
+<dbg> ble_central: notify_func: payload
+                   00 00 05 00 00 00 00 00                          |........
+<dbg> ble_central: notify_func: payload
+                   00 00 00 00 00 00 00 00                          |........
+<dbg> ble_central: notify_func: payload
+                   00 00 00 00 00 00 00 00                          |........
diff --git a/app/tests/ble/profiles/dont-bond-to-taken-profile/centrals.txt b/app/tests/ble/profiles/dont-bond-to-taken-profile/centrals.txt
new file mode 100644
index 00000000..80601bad
--- /dev/null
+++ b/app/tests/ble/profiles/dont-bond-to-taken-profile/centrals.txt
@@ -0,0 +1,2 @@
+./ble_test_central.exe -d=2 -halt_after_bonding
+./ble_test_central.exe -d=3 -wait_on_start=1300
diff --git a/app/tests/ble/profiles/dont-bond-to-taken-profile/events.patterns b/app/tests/ble/profiles/dont-bond-to-taken-profile/events.patterns
new file mode 100644
index 00000000..dbfe5627
--- /dev/null
+++ b/app/tests/ble/profiles/dont-bond-to-taken-profile/events.patterns
@@ -0,0 +1,2 @@
+s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9]  .{19}/profile 0 /p
+s/^d_03: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9]  .{19}/profile 1 /p
diff --git a/app/tests/ble/profiles/dont-bond-to-taken-profile/nrf52_bsim.keymap b/app/tests/ble/profiles/dont-bond-to-taken-profile/nrf52_bsim.keymap
new file mode 100644
index 00000000..7c67425e
--- /dev/null
+++ b/app/tests/ble/profiles/dont-bond-to-taken-profile/nrf52_bsim.keymap
@@ -0,0 +1,24 @@
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/kscan_mock.h>
+
+&kscan {
+    events =
+    <ZMK_MOCK_PRESS(0,0,10000)
+    ZMK_MOCK_RELEASE(0,0,2000)
+    ZMK_MOCK_PRESS(0,1,100)
+    ZMK_MOCK_RELEASE(0,1,1000)>;
+};
+
+/ {
+    keymap {
+        compatible = "zmk,keymap";
+
+        default_layer {
+            bindings = <
+            &kp A &kp B
+            &bt BT_SEL 0 &bt BT_SEL 1>;
+        };
+    };
+};
diff --git a/app/tests/ble/profiles/dont-bond-to-taken-profile/snapshot.log b/app/tests/ble/profiles/dont-bond-to-taken-profile/snapshot.log
new file mode 100644
index 00000000..d41eae79
--- /dev/null
+++ b/app/tests/ble/profiles/dont-bond-to-taken-profile/snapshot.log
@@ -0,0 +1,23 @@
+profile 0 <wrn> bt_id: No static addresses stored in controller
+profile 0 <dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
+profile 0 <dbg> ble_central: start_scan: [Scanning successfully started]
+profile 0 <dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+profile 0 <dbg> ble_central: eir_found: [AD]: 9 data_len 0
+profile 0 <dbg> ble_central: eir_found: [AD]: 25 data_len 2
+profile 0 <dbg> ble_central: eir_found: [AD]: 1 data_len 1
+profile 0 <dbg> ble_central: eir_found: [AD]: 2 data_len 4
+profile 0 <dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+profile 0 <dbg> ble_central: connected: [Setting the security for the connection]
+profile 0 <dbg> ble_central: pairing_complete: Pairing complete
+profile 1 <wrn> bt_id: No static addresses stored in controller
+profile 1 <dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
+profile 1 <dbg> ble_central: start_scan: [Scanning successfully started]
+profile 1 <dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+profile 1 <dbg> ble_central: eir_found: [AD]: 9 data_len 0
+profile 1 <dbg> ble_central: eir_found: [AD]: 25 data_len 2
+profile 1 <dbg> ble_central: eir_found: [AD]: 1 data_len 1
+profile 1 <dbg> ble_central: eir_found: [AD]: 2 data_len 4
+profile 1 <dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+profile 1 <dbg> ble_central: connected: [Setting the security for the connection]
+profile 1 <err> bt_smp: reason 0x8
+profile 1 <dbg> ble_central: security_changed: [Security Change Failed]
diff --git a/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/centrals.txt b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/centrals.txt
new file mode 100644
index 00000000..e60cdec0
--- /dev/null
+++ b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/centrals.txt
@@ -0,0 +1,2 @@
+./ble_test_central.exe -d=2
+./ble_test_central.exe -d=3 -wait_on_start=1300
diff --git a/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/events.patterns b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/events.patterns
new file mode 100644
index 00000000..dbfe5627
--- /dev/null
+++ b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/events.patterns
@@ -0,0 +1,2 @@
+s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9]  .{19}/profile 0 /p
+s/^d_03: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9]  .{19}/profile 1 /p
diff --git a/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/nrf52_bsim.keymap b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/nrf52_bsim.keymap
new file mode 100644
index 00000000..de6884ae
--- /dev/null
+++ b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/nrf52_bsim.keymap
@@ -0,0 +1,26 @@
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/kscan_mock.h>
+
+&kscan {
+    events =
+    <ZMK_MOCK_PRESS(0,0,5000)
+    ZMK_MOCK_RELEASE(0,0,200)
+    ZMK_MOCK_PRESS(1,1,10)
+    ZMK_MOCK_RELEASE(1,1,2000)
+    ZMK_MOCK_PRESS(0,1,1000)
+    ZMK_MOCK_RELEASE(0,1,1000)>;
+};
+
+/ {
+    keymap {
+        compatible = "zmk,keymap";
+
+        default_layer {
+            bindings = <
+            &kp A &kp B
+            &bt BT_SEL 0 &bt BT_SEL 1>;
+        };
+    };
+};
diff --git a/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/snapshot.log b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/snapshot.log
new file mode 100644
index 00000000..a03bbb09
--- /dev/null
+++ b/app/tests/ble/profiles/first-and-second-profile-paired-then-send-data/snapshot.log
@@ -0,0 +1,42 @@
+profile 0 <wrn> bt_id: No static addresses stored in controller
+profile 0 <dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
+profile 0 <dbg> ble_central: start_scan: [Scanning successfully started]
+profile 0 <dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+profile 0 <dbg> ble_central: eir_found: [AD]: 9 data_len 0
+profile 0 <dbg> ble_central: eir_found: [AD]: 25 data_len 2
+profile 0 <dbg> ble_central: eir_found: [AD]: 1 data_len 1
+profile 0 <dbg> ble_central: eir_found: [AD]: 2 data_len 4
+profile 0 <dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+profile 0 <dbg> ble_central: connected: [Setting the security for the connection]
+profile 0 <dbg> ble_central: pairing_complete: Pairing complete
+profile 0 <dbg> ble_central: discover_conn: [Discovery started for conn]
+profile 0 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 23
+profile 1 <wrn> bt_id: No static addresses stored in controller
+profile 1 <dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
+profile 1 <dbg> ble_central: start_scan: [Scanning successfully started]
+profile 0 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 28
+profile 0 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 30
+profile 0 <dbg> ble_central: discover_func: [SUBSCRIBED]
+profile 0 <dbg> ble_central: notify_func: payload
+profile 0                    00 00 04 00 00 00 00 00                          |........
+profile 0 <dbg> ble_central: notify_func: payload
+profile 0                    00 00 00 00 00 00 00 00                          |........
+profile 1 <dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+profile 1 <dbg> ble_central: eir_found: [AD]: 9 data_len 0
+profile 1 <dbg> ble_central: eir_found: [AD]: 25 data_len 2
+profile 1 <dbg> ble_central: eir_found: [AD]: 1 data_len 1
+profile 1 <dbg> ble_central: eir_found: [AD]: 2 data_len 4
+profile 1 <dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+profile 1 <dbg> ble_central: connected: [Setting the security for the connection]
+profile 1 <dbg> ble_central: pairing_complete: Pairing complete
+profile 1 <dbg> ble_central: discover_conn: [Discovery started for conn]
+profile 1 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 23
+profile 1 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 28
+profile 1 <dbg> ble_central: discover_func: [ATTRIBUTE] handle 30
+profile 1 <dbg> ble_central: discover_func: [SUBSCRIBED]
+profile 1 <dbg> ble_central: notify_func: payload
+profile 1                    00 00 05 00 00 00 00 00                          |........
+profile 1 <dbg> ble_central: notify_func: payload
+profile 1                    00 00 00 00 00 00 00 00                          |........
+profile 1 <dbg> ble_central: notify_func: payload
+profile 1                    00 00 00 00 00 00 00 00                          |........
diff --git a/app/tests/ble/profiles/reconnect-then-output-to-selection/centrals.txt b/app/tests/ble/profiles/reconnect-then-output-to-selection/centrals.txt
new file mode 100644
index 00000000..24781185
--- /dev/null
+++ b/app/tests/ble/profiles/reconnect-then-output-to-selection/centrals.txt
@@ -0,0 +1 @@
+./ble_test_central.exe -d=2 -disconnect_and_reconnect
diff --git a/app/tests/ble/profiles/reconnect-then-output-to-selection/events.patterns b/app/tests/ble/profiles/reconnect-then-output-to-selection/events.patterns
new file mode 100644
index 00000000..cca5a2d4
--- /dev/null
+++ b/app/tests/ble/profiles/reconnect-then-output-to-selection/events.patterns
@@ -0,0 +1 @@
+s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9]  .{19}//p
diff --git a/app/tests/ble/profiles/reconnect-then-output-to-selection/nrf52_bsim.keymap b/app/tests/ble/profiles/reconnect-then-output-to-selection/nrf52_bsim.keymap
new file mode 100644
index 00000000..7c67425e
--- /dev/null
+++ b/app/tests/ble/profiles/reconnect-then-output-to-selection/nrf52_bsim.keymap
@@ -0,0 +1,24 @@
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/kscan_mock.h>
+
+&kscan {
+    events =
+    <ZMK_MOCK_PRESS(0,0,10000)
+    ZMK_MOCK_RELEASE(0,0,2000)
+    ZMK_MOCK_PRESS(0,1,100)
+    ZMK_MOCK_RELEASE(0,1,1000)>;
+};
+
+/ {
+    keymap {
+        compatible = "zmk,keymap";
+
+        default_layer {
+            bindings = <
+            &kp A &kp B
+            &bt BT_SEL 0 &bt BT_SEL 1>;
+        };
+    };
+};
diff --git a/app/tests/ble/profiles/reconnect-then-output-to-selection/snapshot.log b/app/tests/ble/profiles/reconnect-then-output-to-selection/snapshot.log
new file mode 100644
index 00000000..bf6cc49e
--- /dev/null
+++ b/app/tests/ble/profiles/reconnect-then-output-to-selection/snapshot.log
@@ -0,0 +1,35 @@
+<wrn> bt_id: No static addresses stored in controller
+<dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
+<dbg> ble_central: start_scan: [Scanning successfully started]
+<dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+<dbg> ble_central: eir_found: [AD]: 9 data_len 0
+<dbg> ble_central: eir_found: [AD]: 25 data_len 2
+<dbg> ble_central: eir_found: [AD]: 1 data_len 1
+<dbg> ble_central: eir_found: [AD]: 2 data_len 4
+<dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+<dbg> ble_central: connected: [Setting the security for the connection]
+<dbg> ble_central: pairing_complete: Pairing complete
+<dbg> ble_central: disconnected: [Disconnected]: ED:3B:20:15:18:12 (random) (reason 0x16)
+<dbg> ble_central: start_scan: [Scanning successfully started]
+<dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
+<dbg> ble_central: eir_found: [AD]: 9 data_len 0
+<dbg> ble_central: eir_found: [AD]: 25 data_len 2
+<dbg> ble_central: eir_found: [AD]: 1 data_len 1
+<dbg> ble_central: eir_found: [AD]: 2 data_len 4
+<dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
+<dbg> ble_central: connected: [Setting the security for the connection]
+<dbg> ble_central: discover_conn: [Discovery started for conn]
+<dbg> ble_central: discover_func: [ATTRIBUTE] handle 23
+<dbg> ble_central: discover_func: [ATTRIBUTE] handle 28
+<dbg> ble_central: discover_func: [ATTRIBUTE] handle 30
+<dbg> ble_central: discover_func: [SUBSCRIBED]
+<dbg> ble_central: notify_func: payload
+                   00 00 04 00 00 00 00 00                          |........
+<dbg> ble_central: notify_func: payload
+                   00 00 00 00 00 00 00 00                          |........
+<dbg> ble_central: notify_func: payload
+                   00 00 05 00 00 00 00 00                          |........
+<dbg> ble_central: notify_func: payload
+                   00 00 00 00 00 00 00 00                          |........
+<dbg> ble_central: notify_func: payload
+                   00 00 00 00 00 00 00 00                          |........
diff --git a/app/tests/caps-word/behavior_keymap.dtsi b/app/tests/caps-word/behavior_keymap.dtsi
index 855406fc..2e404afb 100644
--- a/app/tests/caps-word/behavior_keymap.dtsi
+++ b/app/tests/caps-word/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/caps-word/continue-with-modifiers/native_posix_64.keymap b/app/tests/caps-word/continue-with-modifiers/native_posix_64.keymap
index bbbdac10..fe5360e6 100644
--- a/app/tests/caps-word/continue-with-modifiers/native_posix_64.keymap
+++ b/app/tests/caps-word/continue-with-modifiers/native_posix_64.keymap
@@ -6,7 +6,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap
index 3438f9bc..6f9f9860 100644
--- a/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap
+++ b/app/tests/combo/combos-and-holdtaps-0/native_posix_64.keymap
@@ -24,7 +24,6 @@ first so the decision to hold or tap can be made.
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap
index 9120e8c3..0982d34b 100644
--- a/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap
+++ b/app/tests/combo/combos-and-holdtaps-1/native_posix_64.keymap
@@ -19,7 +19,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap
index a227fe4c..6feebf2f 100644
--- a/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap
+++ b/app/tests/combo/combos-and-holdtaps-2/native_posix_64.keymap
@@ -26,7 +26,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap
index 4fbf2407..fbbd7a9e 100644
--- a/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap
+++ b/app/tests/combo/combos-and-holdtaps-3/native_posix_64.keymap
@@ -18,7 +18,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap b/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap
index 59f4391f..b3e987cf 100644
--- a/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap
+++ b/app/tests/combo/combos-and-holdtaps-4/native_posix_64.keymap
@@ -22,7 +22,6 @@ ZMK_COMBO(tilde, &kp TILDE,     3 4, 50)
 / {
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/layer-filter-0/native_posix_64.keymap b/app/tests/combo/layer-filter-0/native_posix_64.keymap
index 68077849..12946183 100644
--- a/app/tests/combo/layer-filter-0/native_posix_64.keymap
+++ b/app/tests/combo/layer-filter-0/native_posix_64.keymap
@@ -31,7 +31,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/layer-filter-1/native_posix_64.keymap b/app/tests/combo/layer-filter-1/native_posix_64.keymap
index a11b86ad..6d4a3021 100644
--- a/app/tests/combo/layer-filter-1/native_posix_64.keymap
+++ b/app/tests/combo/layer-filter-1/native_posix_64.keymap
@@ -18,7 +18,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/multiple-timeouts/native_posix_64.keymap b/app/tests/combo/multiple-timeouts/native_posix_64.keymap
index a2edc32f..0e3ae996 100644
--- a/app/tests/combo/multiple-timeouts/native_posix_64.keymap
+++ b/app/tests/combo/multiple-timeouts/native_posix_64.keymap
@@ -19,7 +19,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/overlapping-combos-0/native_posix_64.keymap b/app/tests/combo/overlapping-combos-0/native_posix_64.keymap
index e89a3f22..a9a229fb 100644
--- a/app/tests/combo/overlapping-combos-0/native_posix_64.keymap
+++ b/app/tests/combo/overlapping-combos-0/native_posix_64.keymap
@@ -37,7 +37,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/overlapping-combos-1/native_posix_64.keymap b/app/tests/combo/overlapping-combos-1/native_posix_64.keymap
index 4b0166be..f3b0ab97 100644
--- a/app/tests/combo/overlapping-combos-1/native_posix_64.keymap
+++ b/app/tests/combo/overlapping-combos-1/native_posix_64.keymap
@@ -26,7 +26,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/overlapping-combos-2/native_posix_64.keymap b/app/tests/combo/overlapping-combos-2/native_posix_64.keymap
index 5c38bcfc..beed222e 100644
--- a/app/tests/combo/overlapping-combos-2/native_posix_64.keymap
+++ b/app/tests/combo/overlapping-combos-2/native_posix_64.keymap
@@ -27,7 +27,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/overlapping-combos-3/native_posix_64.keymap b/app/tests/combo/overlapping-combos-3/native_posix_64.keymap
index 48e3397f..2e7e4225 100644
--- a/app/tests/combo/overlapping-combos-3/native_posix_64.keymap
+++ b/app/tests/combo/overlapping-combos-3/native_posix_64.keymap
@@ -28,7 +28,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/overlapping-combos-4-different-timeouts/native_posix_64.keymap b/app/tests/combo/overlapping-combos-4-different-timeouts/native_posix_64.keymap
index 89672079..06a67b88 100644
--- a/app/tests/combo/overlapping-combos-4-different-timeouts/native_posix_64.keymap
+++ b/app/tests/combo/overlapping-combos-4-different-timeouts/native_posix_64.keymap
@@ -32,7 +32,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap b/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap
index 55e8f1e7..d3151382 100644
--- a/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap
+++ b/app/tests/combo/partially-overlapping-combos/native_posix_64.keymap
@@ -26,7 +26,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap b/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap
index da2e9483..85cb6475 100644
--- a/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap
+++ b/app/tests/combo/press-release-long-combo-complete/native_posix_64.keymap
@@ -14,7 +14,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap b/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap
index b1494cec..49b92968 100644
--- a/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap
+++ b/app/tests/combo/press-release-long-combo-incomplete/native_posix_64.keymap
@@ -14,7 +14,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap b/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap
index 87692864..61787322 100644
--- a/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap
+++ b/app/tests/combo/press-release-long-combo-wrong-last-key/native_posix_64.keymap
@@ -14,7 +14,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/press-release/native_posix_64.keymap b/app/tests/combo/press-release/native_posix_64.keymap
index 26cd241b..783dcf00 100644
--- a/app/tests/combo/press-release/native_posix_64.keymap
+++ b/app/tests/combo/press-release/native_posix_64.keymap
@@ -14,7 +14,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/press-timeout/native_posix_64.keymap b/app/tests/combo/press-timeout/native_posix_64.keymap
index a71de45a..c9cd2331 100644
--- a/app/tests/combo/press-timeout/native_posix_64.keymap
+++ b/app/tests/combo/press-timeout/native_posix_64.keymap
@@ -14,7 +14,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap b/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap
index 2e0a67a3..55d93823 100644
--- a/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap
+++ b/app/tests/combo/press1-press2-release1-release2/native_posix_64.keymap
@@ -20,7 +20,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap b/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap
index 8d4838eb..ace63a16 100644
--- a/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap
+++ b/app/tests/combo/press1-press2-release2-release1/native_posix_64.keymap
@@ -20,7 +20,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap b/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap
index 9c75e570..8b59792b 100644
--- a/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap
+++ b/app/tests/combo/press1-release1-press2-release2/native_posix_64.keymap
@@ -20,7 +20,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/require-prior-idle/native_posix_64.keymap b/app/tests/combo/require-prior-idle/native_posix_64.keymap
index fcd94056..72801f74 100644
--- a/app/tests/combo/require-prior-idle/native_posix_64.keymap
+++ b/app/tests/combo/require-prior-idle/native_posix_64.keymap
@@ -21,7 +21,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/slowrelease-disabled/native_posix_64.keymap b/app/tests/combo/slowrelease-disabled/native_posix_64.keymap
index 46b35be0..cfea0cd6 100644
--- a/app/tests/combo/slowrelease-disabled/native_posix_64.keymap
+++ b/app/tests/combo/slowrelease-disabled/native_posix_64.keymap
@@ -15,7 +15,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/combo/slowrelease-enabled/native_posix_64.keymap b/app/tests/combo/slowrelease-enabled/native_posix_64.keymap
index d64876da..e57bae60 100644
--- a/app/tests/combo/slowrelease-enabled/native_posix_64.keymap
+++ b/app/tests/combo/slowrelease-enabled/native_posix_64.keymap
@@ -15,7 +15,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/gresc/gresc-press-release/native_posix_64.keymap b/app/tests/gresc/gresc-press-release/native_posix_64.keymap
index c472dd6d..5280543d 100644
--- a/app/tests/gresc/gresc-press-release/native_posix_64.keymap
+++ b/app/tests/gresc/gresc-press-release/native_posix_64.keymap
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/gresc/gresc-two-instances/native_posix_64.keymap b/app/tests/gresc/gresc-two-instances/native_posix_64.keymap
index 14adcf45..5cb0695c 100644
--- a/app/tests/gresc/gresc-two-instances/native_posix_64.keymap
+++ b/app/tests/gresc/gresc-two-instances/native_posix_64.keymap
@@ -13,7 +13,6 @@ The first gresc that is released releases the key.
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/balanced/6-retro-tap/native_posix_64.keymap b/app/tests/hold-tap/balanced/6-retro-tap/native_posix_64.keymap
index 51995f8d..f9bda1cf 100644
--- a/app/tests/hold-tap/balanced/6-retro-tap/native_posix_64.keymap
+++ b/app/tests/hold-tap/balanced/6-retro-tap/native_posix_64.keymap
@@ -6,7 +6,6 @@
     behaviors {
         ht_bal: behavior_balanced {
             compatible = "zmk,behavior-hold-tap";
-            label = "MOD_TAP";
             #binding-cells = <2>;
             flavor = "balanced";
             tapping_term_ms = <300>;
@@ -17,7 +16,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi b/app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi
index c750f8e3..9acf5a1b 100644
--- a/app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/balanced/7-positional/behavior_keymap.dtsi
@@ -6,7 +6,6 @@
     behaviors {
         ht_bal: behavior_hold_tap_balanced {
             compatible = "zmk,behavior-hold-tap";
-            label = "HOLD_TAP_BALANCED";
             #binding-cells = <2>;
             flavor = "balanced";
             tapping-term-ms = <300>;
@@ -18,7 +17,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/balanced/8-require-prior-idle/behavior_keymap.dtsi b/app/tests/hold-tap/balanced/8-require-prior-idle/behavior_keymap.dtsi
index 670bdcc2..0bcb27c5 100644
--- a/app/tests/hold-tap/balanced/8-require-prior-idle/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/balanced/8-require-prior-idle/behavior_keymap.dtsi
@@ -6,7 +6,6 @@
     behaviors {
         ht_bal: behavior_balanced {
             compatible = "zmk,behavior-hold-tap";
-            label = "MOD_TAP";
             #binding-cells = <2>;
             flavor = "balanced";
             tapping-term-ms = <300>;
@@ -18,7 +17,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/balanced/behavior_keymap.dtsi b/app/tests/hold-tap/balanced/behavior_keymap.dtsi
index 9f338ebc..350dfaf3 100644
--- a/app/tests/hold-tap/balanced/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/balanced/behavior_keymap.dtsi
@@ -6,7 +6,6 @@
     behaviors {
         ht_bal: behavior_hold_tap_balanced {
             compatible = "zmk,behavior-hold-tap";
-            label = "HOLD_TAP_BALANCED";
             #binding-cells = <2>;
             flavor = "balanced";
             tapping-term-ms = <300>;
@@ -17,7 +16,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/balanced/many-nested/native_posix_64.keymap b/app/tests/hold-tap/balanced/many-nested/native_posix_64.keymap
index 4bac8b83..cfbb128f 100644
--- a/app/tests/hold-tap/balanced/many-nested/native_posix_64.keymap
+++ b/app/tests/hold-tap/balanced/many-nested/native_posix_64.keymap
@@ -6,7 +6,6 @@
     behaviors {
         ht_bal: behavior_hold_tap_balanced {
             compatible = "zmk,behavior-hold-tap";
-            label = "HOLD_TAP_BALANCED";
             #binding-cells = <2>;
             flavor = "balanced";
             tapping-term-ms = <300>;
@@ -16,7 +15,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/hold-preferred/6-retro-tap/native_posix_64.keymap b/app/tests/hold-tap/hold-preferred/6-retro-tap/native_posix_64.keymap
index 8dbc7d82..8aa29dec 100644
--- a/app/tests/hold-tap/hold-preferred/6-retro-tap/native_posix_64.keymap
+++ b/app/tests/hold-tap/hold-preferred/6-retro-tap/native_posix_64.keymap
@@ -6,7 +6,6 @@
     behaviors {
         hp: behavior_hold_preferred {
             compatible = "zmk,behavior-hold-tap";
-            label = "MOD_TAP";
             #binding-cells = <2>;
             flavor = "hold-preferred";
             tapping_term_ms = <300>;
@@ -17,7 +16,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi b/app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi
index 71f3aba5..65e7f9aa 100644
--- a/app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/hold-preferred/7-positional/behavior_keymap.dtsi
@@ -6,7 +6,6 @@
     behaviors {
         ht_hold: behavior_hold_hold_tap {
             compatible = "zmk,behavior-hold-tap";
-            label = "hold_hold_tap";
             #binding-cells = <2>;
             flavor = "hold-preferred";
             tapping-term-ms = <300>;
@@ -18,7 +17,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/hold-preferred/8-require-prior-idle/behavior_keymap.dtsi b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/behavior_keymap.dtsi
index a99eb3f5..bdc6838a 100644
--- a/app/tests/hold-tap/hold-preferred/8-require-prior-idle/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/hold-preferred/8-require-prior-idle/behavior_keymap.dtsi
@@ -6,7 +6,6 @@
     behaviors {
         hp: behavior_hold_preferred {
             compatible = "zmk,behavior-hold-tap";
-            label = "MOD_TAP";
             #binding-cells = <2>;
             flavor = "hold-preferred";
             tapping-term-ms = <300>;
@@ -18,7 +17,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/hold-preferred/behavior_keymap.dtsi b/app/tests/hold-tap/hold-preferred/behavior_keymap.dtsi
index da6b8362..702a96b4 100644
--- a/app/tests/hold-tap/hold-preferred/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/hold-preferred/behavior_keymap.dtsi
@@ -8,7 +8,6 @@
     behaviors {
         ht_hold: behavior_hold_hold_tap {
             compatible = "zmk,behavior-hold-tap";
-            label = "hold_hold_tap";
             #binding-cells = <2>;
             flavor = "hold-preferred";
             tapping-term-ms = <300>;
@@ -19,7 +18,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/tap-preferred/6-nested-timeouts/native_posix_64.keymap b/app/tests/hold-tap/tap-preferred/6-nested-timeouts/native_posix_64.keymap
index 500d2670..85c9a959 100644
--- a/app/tests/hold-tap/tap-preferred/6-nested-timeouts/native_posix_64.keymap
+++ b/app/tests/hold-tap/tap-preferred/6-nested-timeouts/native_posix_64.keymap
@@ -12,7 +12,6 @@
     behaviors {
         tp_short: short_tap {
             compatible = "zmk,behavior-hold-tap";
-            label = "MOD_TAP_SHORT";
             #binding-cells = <2>;
             flavor = "tap-preferred";
             tapping-term-ms = <100>;
@@ -21,7 +20,6 @@
         };
         tp_long: long_tap {
             compatible = "zmk,behavior-hold-tap";
-            label = "MOD_TAP_LONG";
             #binding-cells = <2>;
             flavor = "tap-preferred";
             tapping-term-ms = <200>;
@@ -32,7 +30,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi b/app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi
index 79a88eb2..3e891f2c 100644
--- a/app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/tap-preferred/7-positional/behavior_keymap.dtsi
@@ -6,7 +6,6 @@
     behaviors {
         tp: behavior_tap_preferred {
             compatible = "zmk,behavior-hold-tap";
-            label = "MOD_TAP";
             #binding-cells = <2>;
             flavor = "tap-preferred";
             tapping-term-ms = <300>;
@@ -18,7 +17,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/tap-preferred/8-require-prior-idle/behavior_keymap.dtsi b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/behavior_keymap.dtsi
index c66dc934..23ecd2df 100644
--- a/app/tests/hold-tap/tap-preferred/8-require-prior-idle/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/tap-preferred/8-require-prior-idle/behavior_keymap.dtsi
@@ -6,7 +6,6 @@
     behaviors {
         tp: behavior_tap_preferred {
             compatible = "zmk,behavior-hold-tap";
-            label = "MOD_TAP";
             #binding-cells = <2>;
             flavor = "tap-preferred";
             tapping-term-ms = <300>;
@@ -18,7 +17,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/tap-preferred/behavior_keymap.dtsi b/app/tests/hold-tap/tap-preferred/behavior_keymap.dtsi
index df307740..fbe6c95d 100644
--- a/app/tests/hold-tap/tap-preferred/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/tap-preferred/behavior_keymap.dtsi
@@ -6,7 +6,6 @@
     behaviors {
         tp: behavior_tap_preferred {
             compatible = "zmk,behavior-hold-tap";
-            label = "MOD_TAP";
             #binding-cells = <2>;
             flavor = "tap-preferred";
             tapping-term-ms = <300>;
@@ -17,7 +16,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/behavior_keymap.dtsi b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/behavior_keymap.dtsi
index 7aa39408..6a78d588 100644
--- a/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/tap-unless-interrupted/6-require-prior-idle/behavior_keymap.dtsi
@@ -6,7 +6,6 @@
     behaviors {
         ht_tui: behavior_hold_tap_tap_unless_interrupted {
             compatible = "zmk,behavior-hold-tap";
-            label = "hold_tap_tap_unless_interrupted";
             #binding-cells = <2>;
             flavor = "tap-unless-interrupted";
             tapping-term-ms = <300>;
@@ -18,7 +17,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/hold-tap/tap-unless-interrupted/behavior_keymap.dtsi b/app/tests/hold-tap/tap-unless-interrupted/behavior_keymap.dtsi
index b24de6dd..7616c462 100644
--- a/app/tests/hold-tap/tap-unless-interrupted/behavior_keymap.dtsi
+++ b/app/tests/hold-tap/tap-unless-interrupted/behavior_keymap.dtsi
@@ -8,7 +8,6 @@
     behaviors {
         ht_tui: behavior_hold_tap_tap_unless_interrupted {
             compatible = "zmk,behavior-hold-tap";
-            label = "hold_tap_tap_unless_interrupted";
             #binding-cells = <2>;
             flavor = "tap-unless-interrupted";
             tapping-term-ms = <300>;
@@ -19,7 +18,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/key-repeat/behavior_keymap.dtsi b/app/tests/key-repeat/behavior_keymap.dtsi
index c8e2d9c4..a0e5c8f9 100644
--- a/app/tests/key-repeat/behavior_keymap.dtsi
+++ b/app/tests/key-repeat/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/keypress/behavior_keymap.dtsi b/app/tests/keypress/behavior_keymap.dtsi
index 52f9421c..5f7cfd2d 100644
--- a/app/tests/keypress/behavior_keymap.dtsi
+++ b/app/tests/keypress/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/keytoggle/behavior_keymap.dtsi b/app/tests/keytoggle/behavior_keymap.dtsi
index 45d48164..a8e75136 100644
--- a/app/tests/keytoggle/behavior_keymap.dtsi
+++ b/app/tests/keytoggle/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/keytoggle/kt-alt-tab/native_posix_64.keymap b/app/tests/keytoggle/kt-alt-tab/native_posix_64.keymap
index 4f70b591..78b4e455 100644
--- a/app/tests/keytoggle/kt-alt-tab/native_posix_64.keymap
+++ b/app/tests/keytoggle/kt-alt-tab/native_posix_64.keymap
@@ -36,7 +36,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/keytoggle/kt-modded-alpha/native_posix_64.keymap b/app/tests/keytoggle/kt-modded-alpha/native_posix_64.keymap
index b07f297f..0621b33a 100644
--- a/app/tests/keytoggle/kt-modded-alpha/native_posix_64.keymap
+++ b/app/tests/keytoggle/kt-modded-alpha/native_posix_64.keymap
@@ -26,7 +26,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/macros/basic/keycode_events.snapshot b/app/tests/macros/basic/keycode_events.snapshot
index b238a2ff..5639f1d7 100644
--- a/app/tests/macros/basic/keycode_events.snapshot
+++ b/app/tests/macros/basic/keycode_events.snapshot
@@ -1,18 +1,18 @@
-queue_process_next: Invoking KEY_PRESS: 0x70004 0x00
+queue_process_next: Invoking key_press: 0x70004 0x00
 kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 50ms
-queue_process_next: Invoking KEY_PRESS: 0x70004 0x00
+queue_process_next: Invoking key_press: 0x70004 0x00
 kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 10ms
-queue_process_next: Invoking KEY_PRESS: 0x70005 0x00
+queue_process_next: Invoking key_press: 0x70005 0x00
 kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 50ms
-queue_process_next: Invoking KEY_PRESS: 0x70005 0x00
+queue_process_next: Invoking key_press: 0x70005 0x00
 kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 10ms
-queue_process_next: Invoking KEY_PRESS: 0x70006 0x00
+queue_process_next: Invoking key_press: 0x70006 0x00
 kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 50ms
-queue_process_next: Invoking KEY_PRESS: 0x70006 0x00
+queue_process_next: Invoking key_press: 0x70006 0x00
 kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 10ms
diff --git a/app/tests/macros/behavior_keymap.dtsi b/app/tests/macros/behavior_keymap.dtsi
index 90322e42..25414216 100644
--- a/app/tests/macros/behavior_keymap.dtsi
+++ b/app/tests/macros/behavior_keymap.dtsi
@@ -49,7 +49,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/macros/mo-plus-modifier-from-hold-tap/native_posix_64.keymap b/app/tests/macros/mo-plus-modifier-from-hold-tap/native_posix_64.keymap
index bdf89abf..d9d186ce 100644
--- a/app/tests/macros/mo-plus-modifier-from-hold-tap/native_posix_64.keymap
+++ b/app/tests/macros/mo-plus-modifier-from-hold-tap/native_posix_64.keymap
@@ -24,7 +24,6 @@
     behaviors {
         mth: macro_tap_hold {
             compatible = "zmk,behavior-hold-tap";
-            label = "MACRO_TAP_HOLD";
             #binding-cells = <2>;
             flavor = "tap-unless-interrupted";
             tapping-term-ms = <200>;
@@ -34,7 +33,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/macros/mo-plus-modifier-macro/native_posix_64.keymap b/app/tests/macros/mo-plus-modifier-macro/native_posix_64.keymap
index 4cc60bf5..bb06d2c3 100644
--- a/app/tests/macros/mo-plus-modifier-macro/native_posix_64.keymap
+++ b/app/tests/macros/mo-plus-modifier-macro/native_posix_64.keymap
@@ -23,7 +23,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/macros/place-holder-parameters/native_posix_64.keymap b/app/tests/macros/place-holder-parameters/native_posix_64.keymap
index 59d78b5e..c6fcd5c6 100644
--- a/app/tests/macros/place-holder-parameters/native_posix_64.keymap
+++ b/app/tests/macros/place-holder-parameters/native_posix_64.keymap
@@ -12,7 +12,6 @@
     macros {
         slash_macro: slash_macro {
             #binding-cells = <2>;
-            label = "ZM_SLASH";
             compatible = "zmk,behavior-macro-two-param";
             wait-ms = <40>;
             tap-ms = <40>;
@@ -24,7 +23,6 @@
 
         to_second_macro: to_second_macro {
             #binding-cells = <2>;
-            label = "ZMK_TO_SECOND";
             compatible = "zmk,behavior-macro-two-param";
             wait-ms = <40>;
             tap-ms = <40>;
@@ -35,7 +33,6 @@
 
         quote_letter_macro: quote_letter_macro {
             #binding-cells = <1>;
-            label = "ZMK_QLET";
             compatible = "zmk,behavior-macro-one-param";
             wait-ms = <40>;
             tap-ms = <40>;
@@ -48,7 +45,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/macros/press-mid-macro/keycode_events.snapshot b/app/tests/macros/press-mid-macro/keycode_events.snapshot
index 22393a3a..0ec7ccb3 100644
--- a/app/tests/macros/press-mid-macro/keycode_events.snapshot
+++ b/app/tests/macros/press-mid-macro/keycode_events.snapshot
@@ -1,8 +1,8 @@
-pos_state: layer: 0 position: 0, binding name: ZM_abc_macro
+pos_state: layer: 0 position: 0, binding name: abc_macro
 kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
-pos_state: layer: 0 position: 0, binding name: ZM_abc_macro
-pos_state: layer: 0 position: 1, binding name: MO
-pos_state: layer: 0 position: 1, binding name: MO
+pos_state: layer: 0 position: 0, binding name: abc_macro
+pos_state: layer: 0 position: 1, binding name: momentary_layer
+pos_state: layer: 0 position: 1, binding name: momentary_layer
 kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
 kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
 kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
diff --git a/app/tests/macros/timing-override/keycode_events.snapshot b/app/tests/macros/timing-override/keycode_events.snapshot
index 0ff45904..e275cf9b 100644
--- a/app/tests/macros/timing-override/keycode_events.snapshot
+++ b/app/tests/macros/timing-override/keycode_events.snapshot
@@ -1,18 +1,18 @@
-queue_process_next: Invoking KEY_PRESS: 0x70004 0x00
+queue_process_next: Invoking key_press: 0x70004 0x00
 kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 30ms
-queue_process_next: Invoking KEY_PRESS: 0x70004 0x00
+queue_process_next: Invoking key_press: 0x70004 0x00
 kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 50ms
-queue_process_next: Invoking KEY_PRESS: 0x70005 0x00
+queue_process_next: Invoking key_press: 0x70005 0x00
 kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 20ms
-queue_process_next: Invoking KEY_PRESS: 0x70005 0x00
+queue_process_next: Invoking key_press: 0x70005 0x00
 kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 50ms
-queue_process_next: Invoking KEY_PRESS: 0x70006 0x00
+queue_process_next: Invoking key_press: 0x70006 0x00
 kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 20ms
-queue_process_next: Invoking KEY_PRESS: 0x70006 0x00
+queue_process_next: Invoking key_press: 0x70006 0x00
 kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 50ms
diff --git a/app/tests/macros/wait-macro-release/keycode_events.snapshot b/app/tests/macros/wait-macro-release/keycode_events.snapshot
index 21d47a29..abe9791f 100644
--- a/app/tests/macros/wait-macro-release/keycode_events.snapshot
+++ b/app/tests/macros/wait-macro-release/keycode_events.snapshot
@@ -1,16 +1,16 @@
 qm: Iterating macro bindings - starting: 0, count: 4
-queue_process_next: Invoking KEY_PRESS: 0x700e2 0x00
+queue_process_next: Invoking key_press: 0x700e2 0x00
 kp_pressed: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 10ms
-queue_process_next: Invoking KEY_PRESS: 0x7002b 0x00
+queue_process_next: Invoking key_press: 0x7002b 0x00
 kp_pressed: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 40ms
-queue_process_next: Invoking KEY_PRESS: 0x7002b 0x00
+queue_process_next: Invoking key_press: 0x7002b 0x00
 kp_released: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 10ms
 kp_pressed: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00
 kp_released: usage_page 0x07 keycode 0x2B implicit_mods 0x00 explicit_mods 0x00
 qm: Iterating macro bindings - starting: 5, count: 2
-queue_process_next: Invoking KEY_PRESS: 0x700e2 0x00
+queue_process_next: Invoking key_press: 0x700e2 0x00
 kp_released: usage_page 0x07 keycode 0xE2 implicit_mods 0x00 explicit_mods 0x00
 queue_process_next: Processing next queued behavior in 0ms
diff --git a/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/native_posix_64.keymap b/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/native_posix_64.keymap
index 66fb1ed0..8f7b2cdb 100644
--- a/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/native_posix_64.keymap
+++ b/app/tests/mod-morph/2b-masked-morph-implicit-overwrite/native_posix_64.keymap
@@ -6,7 +6,6 @@
     behaviors {
         mod_morph: mod_morph {
             compatible = "zmk,behavior-mod-morph";
-            label = "MOD_MORPH_TEST";
             #binding-cells = <0>;
             bindings = <&kp A>, <&kp LS(B)>;  // implict mod overwrite
             mods = <(MOD_LSFT|MOD_RSFT)>;
@@ -15,7 +14,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/native_posix_64.keymap b/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/native_posix_64.keymap
index 9b7f4fe1..4f9f4910 100644
--- a/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/native_posix_64.keymap
+++ b/app/tests/mod-morph/2d-masked-morph-into-hold-tap-tap/native_posix_64.keymap
@@ -16,7 +16,6 @@
     behaviors {
         mod_morph: mod_morph {
             compatible = "zmk,behavior-mod-morph";
-            label = "MOD_MORPH_TEST";
             #binding-cells = <0>;
             bindings = <&kp A>, <&lt 1 B>;
             mods = <(MOD_LSFT|MOD_RSFT)>;
@@ -26,7 +25,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/native_posix_64.keymap b/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/native_posix_64.keymap
index e0c1d1e5..77067f34 100644
--- a/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/native_posix_64.keymap
+++ b/app/tests/mod-morph/2e-masked-morph-into-hold-tap-hold/native_posix_64.keymap
@@ -18,7 +18,6 @@
     behaviors {
         mod_morph: mod_morph {
             compatible = "zmk,behavior-mod-morph";
-            label = "MOD_MORPH_TEST";
             #binding-cells = <0>;
             bindings = <&kp A>, <&lt 1 B>;
             mods = <(MOD_LSFT|MOD_RSFT)>;
@@ -28,7 +27,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/mod-morph/3-unmasked-morph/native_posix_64.keymap b/app/tests/mod-morph/3-unmasked-morph/native_posix_64.keymap
index a20c04d5..d2ad5670 100644
--- a/app/tests/mod-morph/3-unmasked-morph/native_posix_64.keymap
+++ b/app/tests/mod-morph/3-unmasked-morph/native_posix_64.keymap
@@ -6,7 +6,6 @@
     behaviors {
         mod_morph: mod_morph {
             compatible = "zmk,behavior-mod-morph";
-            label = "MOD_MORPH_TEST";
             #binding-cells = <0>;
             bindings = <&kp A>, <&kp B>;
             mods = <(MOD_LSFT|MOD_RSFT)>;
@@ -16,7 +15,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/mod-morph/behavior_keymap.dtsi b/app/tests/mod-morph/behavior_keymap.dtsi
index 2f880540..86150307 100644
--- a/app/tests/mod-morph/behavior_keymap.dtsi
+++ b/app/tests/mod-morph/behavior_keymap.dtsi
@@ -2,7 +2,6 @@
     behaviors {
         mod_morph: mod_morph {
             compatible = "zmk,behavior-mod-morph";
-            label = "MOD_MORPH_TEST";
             #binding-cells = <0>;
             bindings = <&kp A>, <&kp B>;
             mods = <(MOD_LSFT|MOD_RSFT)>;
@@ -11,7 +10,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap
index 72b218f5..8060f18f 100644
--- a/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap
+++ b/app/tests/modifiers/explicit/kp-hyper-dn-a-dn-a-up-hyper-up/native_posix_64.keymap
@@ -16,7 +16,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/native_posix_64.keymap
index d68f8921..503c3519 100644
--- a/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/native_posix_64.keymap
+++ b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-dn-lctl-up-lctl-up/native_posix_64.keymap
@@ -15,7 +15,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/native_posix_64.keymap
index c2d12eb2..362754c8 100644
--- a/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/native_posix_64.keymap
+++ b/app/tests/modifiers/explicit/kp-lctl-dn-lctl-up/native_posix_64.keymap
@@ -13,7 +13,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/native_posix_64.keymap
index 7be62b94..f25996f6 100644
--- a/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/native_posix_64.keymap
+++ b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lctl-up-lsft-up/native_posix_64.keymap
@@ -15,7 +15,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/native_posix_64.keymap b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/native_posix_64.keymap
index 8d1d773e..15cdc5c9 100644
--- a/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/native_posix_64.keymap
+++ b/app/tests/modifiers/explicit/kp-lctl-dn-lsft-dn-lsft-up-lctl-up/native_posix_64.keymap
@@ -16,7 +16,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/native_posix_64.keymap b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/native_posix_64.keymap
index 87101d83..17d949e7 100644
--- a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/native_posix_64.keymap
+++ b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod1-up-mod2-up/native_posix_64.keymap
@@ -15,7 +15,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/native_posix_64.keymap b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/native_posix_64.keymap
index 6b40fef1..fa34be42 100644
--- a/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/native_posix_64.keymap
+++ b/app/tests/modifiers/implicit/kp-mod1-dn-mod2-dn-mod2-up-mod1-up/native_posix_64.keymap
@@ -15,7 +15,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/native_posix_64.keymap b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/native_posix_64.keymap
index 3926eb57..214cff49 100644
--- a/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/native_posix_64.keymap
+++ b/app/tests/modifiers/implicit/kp-rolling-symbols-same-key/native_posix_64.keymap
@@ -15,7 +15,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/native_posix_64.keymap b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/native_posix_64.keymap
index 4b2ca139..01387e54 100644
--- a/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/native_posix_64.keymap
+++ b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-lctl-up-mod-up/native_posix_64.keymap
@@ -15,7 +15,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/native_posix_64.keymap b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/native_posix_64.keymap
index a2564762..113fc488 100644
--- a/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/native_posix_64.keymap
+++ b/app/tests/modifiers/mixed/kp-lctl-dn-mod-dn-mod-up-lctl-up/native_posix_64.keymap
@@ -15,7 +15,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/momentary-layer/1-normal/native_posix_64.keymap b/app/tests/momentary-layer/1-normal/native_posix_64.keymap
index 387a1322..88c70da9 100644
--- a/app/tests/momentary-layer/1-normal/native_posix_64.keymap
+++ b/app/tests/momentary-layer/1-normal/native_posix_64.keymap
@@ -6,7 +6,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/momentary-layer/2-early-key-release/native_posix_64.keymap b/app/tests/momentary-layer/2-early-key-release/native_posix_64.keymap
index 776fc761..48da33e6 100644
--- a/app/tests/momentary-layer/2-early-key-release/native_posix_64.keymap
+++ b/app/tests/momentary-layer/2-early-key-release/native_posix_64.keymap
@@ -6,7 +6,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/momentary-layer/3-covered/native_posix_64.keymap b/app/tests/momentary-layer/3-covered/native_posix_64.keymap
index a7939d9e..42548533 100644
--- a/app/tests/momentary-layer/3-covered/native_posix_64.keymap
+++ b/app/tests/momentary-layer/3-covered/native_posix_64.keymap
@@ -9,7 +9,6 @@ and the original key is "covered".
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/momentary-layer/4-nested/native_posix_64.keymap b/app/tests/momentary-layer/4-nested/native_posix_64.keymap
index 1f4f0aea..12fb6cdc 100644
--- a/app/tests/momentary-layer/4-nested/native_posix_64.keymap
+++ b/app/tests/momentary-layer/4-nested/native_posix_64.keymap
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/momentary-layer/5-nested-early-key-release/native_posix_64.keymap b/app/tests/momentary-layer/5-nested-early-key-release/native_posix_64.keymap
index 4c8f7890..f1f0afcb 100644
--- a/app/tests/momentary-layer/5-nested-early-key-release/native_posix_64.keymap
+++ b/app/tests/momentary-layer/5-nested-early-key-release/native_posix_64.keymap
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/momentary-layer/behavior_keymap.dtsi b/app/tests/momentary-layer/behavior_keymap.dtsi
index 63127a39..8d63bc13 100644
--- a/app/tests/momentary-layer/behavior_keymap.dtsi
+++ b/app/tests/momentary-layer/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/mouse-keys/mkp/native_posix.keymap b/app/tests/mouse-keys/mkp/native_posix.keymap
index 04316eb3..8e3071d4 100644
--- a/app/tests/mouse-keys/mkp/native_posix.keymap
+++ b/app/tests/mouse-keys/mkp/native_posix.keymap
@@ -6,7 +6,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/mouse-keys/mkp/native_posix_64.keymap b/app/tests/mouse-keys/mkp/native_posix_64.keymap
index 04316eb3..8e3071d4 100644
--- a/app/tests/mouse-keys/mkp/native_posix_64.keymap
+++ b/app/tests/mouse-keys/mkp/native_posix_64.keymap
@@ -6,7 +6,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/none/behavior_keymap.dtsi b/app/tests/none/behavior_keymap.dtsi
index 7a4c099b..162ca992 100644
--- a/app/tests/none/behavior_keymap.dtsi
+++ b/app/tests/none/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/sticky-keys/10-callum-mods-quick-release/native_posix_64.keymap b/app/tests/sticky-keys/10-callum-mods-quick-release/native_posix_64.keymap
index bc541824..560c8424 100644
--- a/app/tests/sticky-keys/10-callum-mods-quick-release/native_posix_64.keymap
+++ b/app/tests/sticky-keys/10-callum-mods-quick-release/native_posix_64.keymap
@@ -9,7 +9,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/sticky-keys/10-callum-mods/native_posix_64.keymap b/app/tests/sticky-keys/10-callum-mods/native_posix_64.keymap
index 9121b188..28f2db3d 100644
--- a/app/tests/sticky-keys/10-callum-mods/native_posix_64.keymap
+++ b/app/tests/sticky-keys/10-callum-mods/native_posix_64.keymap
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap b/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap
index bafdbe38..42bb9cfd 100644
--- a/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap
+++ b/app/tests/sticky-keys/10-sl-sl-kp/native_posix_64.keymap
@@ -10,7 +10,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap b/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap
index 38c8fb4c..93239797 100644
--- a/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap
+++ b/app/tests/sticky-keys/2-sl-dn-up-kcdn-kcup/native_posix_64.keymap
@@ -10,7 +10,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/native_posix_64.keymap b/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/native_posix_64.keymap
index 4da4ad98..69db1635 100644
--- a/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/native_posix_64.keymap
+++ b/app/tests/sticky-keys/8-lsk-osk-combination-quick-release/native_posix_64.keymap
@@ -9,7 +9,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/sticky-keys/8-lsk-osk-combination/native_posix_64.keymap b/app/tests/sticky-keys/8-lsk-osk-combination/native_posix_64.keymap
index d9c49014..9523a75e 100644
--- a/app/tests/sticky-keys/8-lsk-osk-combination/native_posix_64.keymap
+++ b/app/tests/sticky-keys/8-lsk-osk-combination/native_posix_64.keymap
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/sticky-keys/9-sk-dn-up-dn-up/native_posix_64.keymap b/app/tests/sticky-keys/9-sk-dn-up-dn-up/native_posix_64.keymap
index 74678256..67efb6af 100644
--- a/app/tests/sticky-keys/9-sk-dn-up-dn-up/native_posix_64.keymap
+++ b/app/tests/sticky-keys/9-sk-dn-up-dn-up/native_posix_64.keymap
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/sticky-keys/behavior_keymap.dtsi b/app/tests/sticky-keys/behavior_keymap.dtsi
index 9322cb14..182ef58e 100644
--- a/app/tests/sticky-keys/behavior_keymap.dtsi
+++ b/app/tests/sticky-keys/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/tap-dance/behavior_keymap.dtsi b/app/tests/tap-dance/behavior_keymap.dtsi
index ce80e958..66ffdf2e 100644
--- a/app/tests/tap-dance/behavior_keymap.dtsi
+++ b/app/tests/tap-dance/behavior_keymap.dtsi
@@ -6,7 +6,6 @@
     behaviors {
         ht: hold_tap {
             compatible = "zmk,behavior-hold-tap";
-            label = "HOLD_TAP";
             #binding-cells = <2>;
             tapping-term-ms = <200>;
             quick_tap_ms = <0>;
@@ -16,7 +15,6 @@
 
         tdm: tap_dance_mixed {
             compatible = "zmk,behavior-tap-dance";
-            label = "TAP_DANCE_MOD";
             #binding-cells = <0>;
             tapping-term-ms = <200>;
             bindings = <&ht LSHIFT A>, <&ht LALT B>, <&ht LGUI C>;
@@ -24,7 +22,6 @@
 
         tdb: tap_dance_basic {
             compatible = "zmk,behavior-tap-dance";
-            label = "TAP_DANCE_BASIC";
             #binding-cells = <0>;
             tapping-term-ms = <200>;
             bindings = <&kp N1>, <&kp N2>, <&kp N3>;
@@ -32,7 +29,6 @@
 
         td2: tap_dance_basic_2 {
             compatible = "zmk,behavior-tap-dance";
-            label = "TAP_DANCE_BASIC_2";
             #binding-cells = <0>;
             tapping-term-ms = <200>;
             bindings = <&kp A>, <&kp B>, <&kp C>;
@@ -40,7 +36,6 @@
 
         tds: tap_dance_single {
             compatible = "zmk,behavior-tap-dance";
-            label = "TAP_DANCE_SINGlE";
             #binding-cells = <0>;
             tapping-term-ms = <200>;
             bindings = <&kp S>;
@@ -59,7 +54,6 @@
 
     keymap {
         compatible = "zmk,keymap";
-        label = "Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/to-layer/behavior_keymap.dtsi b/app/tests/to-layer/behavior_keymap.dtsi
index 7dc857fe..0be9cb96 100644
--- a/app/tests/to-layer/behavior_keymap.dtsi
+++ b/app/tests/to-layer/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/toggle-layer/behavior_keymap.dtsi b/app/tests/toggle-layer/behavior_keymap.dtsi
index 1ecf8599..1ff4a81f 100644
--- a/app/tests/toggle-layer/behavior_keymap.dtsi
+++ b/app/tests/toggle-layer/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/transparent/behavior_keymap.dtsi b/app/tests/transparent/behavior_keymap.dtsi
index dd5ded90..b70c8421 100644
--- a/app/tests/transparent/behavior_keymap.dtsi
+++ b/app/tests/transparent/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/tests/wpm/behavior_keymap.dtsi b/app/tests/wpm/behavior_keymap.dtsi
index 52f9421c..5f7cfd2d 100644
--- a/app/tests/wpm/behavior_keymap.dtsi
+++ b/app/tests/wpm/behavior_keymap.dtsi
@@ -5,7 +5,6 @@
 / {
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
 
         default_layer {
             bindings = <
diff --git a/app/west.yml b/app/west.yml
index ffa36ca3..f72f2f39 100644
--- a/app/west.yml
+++ b/app/west.yml
@@ -1,9 +1,17 @@
 manifest:
+  defaults:
+    remote: upstream
+
   remotes:
     - name: zephyrproject-rtos
       url-base: https://github.com/zephyrproject-rtos
     - name: zmkfirmware
       url-base: https://github.com/zmkfirmware
+    - name: upstream
+      url-base: https://github.com/zephyrproject-rtos
+    - name: babblesim
+      url-base: https://github.com/BabbleSim
+  group-filter: [-babblesim]
   projects:
     - name: zephyr
       remote: zmkfirmware
@@ -30,5 +38,88 @@ manifest:
           - edtt
           - trusted-firmware-m
           - sof
+    - name: bsim
+      repo-path: babblesim-manifest
+      revision: 908ffde6298a937c6549dbfa843a62caab26bfc5
+      path: tools/bsim
+      groups:
+        - babblesim
+    - name: babblesim_base
+      remote: babblesim
+      repo-path: base.git
+      path: tools/bsim/components
+      revision: 02838ca04c4562e68dc876196828d8121679e537
+      groups:
+        - babblesim
+    - name: babblesim_ext_2G4_libPhyComv1
+      remote: babblesim
+      repo-path: ext_2G4_libPhyComv1.git
+      path: tools/bsim/components/ext_2G4_libPhyComv1
+      revision: 9018113a362fa6c9e8f4b9cab9e5a8f12cc46b94
+      groups:
+        - babblesim
+    - name: babblesim_ext_2G4_phy_v1
+      remote: babblesim
+      repo-path: ext_2G4_phy_v1.git
+      path: tools/bsim/components/ext_2G4_phy_v1
+      revision: cf2d86e736efac4f12fad5093ed2da2c5b406156
+      groups:
+        - babblesim
+    - name: babblesim_ext_2G4_channel_NtNcable
+      remote: babblesim
+      repo-path: ext_2G4_channel_NtNcable.git
+      path: tools/bsim/components/ext_2G4_channel_NtNcable
+      revision: 20a38c997f507b0aa53817aab3d73a462fff7af1
+      groups:
+        - babblesim
+    - name: babblesim_ext_2G4_channel_multiatt
+      remote: babblesim
+      repo-path: ext_2G4_channel_multiatt.git
+      path: tools/bsim/components/ext_2G4_channel_multiatt
+      revision: e09bc2d14b1975f969ad19c6ed23eb20e5dc3d09
+      groups:
+        - babblesim
+    - name: babblesim_ext_2G4_modem_magic
+      remote: babblesim
+      repo-path: ext_2G4_modem_magic.git
+      path: tools/bsim/components/ext_2G4_modem_magic
+      revision: cb70771794f0bf6f262aa474848611c68ae8f1ed
+      groups:
+        - babblesim
+    - name: babblesim_ext_2G4_modem_BLE_simple
+      remote: babblesim
+      repo-path: ext_2G4_modem_BLE_simple.git
+      path: tools/bsim/components/ext_2G4_modem_BLE_simple
+      revision: ce975a3259fd0dd761d371b60435242d54794bad
+      groups:
+        - babblesim
+    - name: babblesim_ext_2G4_device_burst_interferer
+      remote: babblesim
+      repo-path: ext_2G4_device_burst_interferer.git
+      path: tools/bsim/components/ext_2G4_device_burst_interferer
+      revision: 5b5339351d6e6a2368c686c734dc8b2fc65698fc
+      groups:
+        - babblesim
+    - name: babblesim_ext_2G4_device_WLAN_actmod
+      remote: babblesim
+      repo-path: ext_2G4_device_WLAN_actmod.git
+      path: tools/bsim/components/ext_2G4_device_WLAN_actmod
+      revision: 9cb6d8e72695f6b785e57443f0629a18069d6ce4
+      groups:
+        - babblesim
+    - name: babblesim_ext_2G4_device_playback
+      remote: babblesim
+      repo-path: ext_2G4_device_playback.git
+      path: tools/bsim/components/ext_2G4_device_playback
+      revision: 85c645929cf1ce995d8537107d9dcbd12ed64036
+      groups:
+        - babblesim
+    - name: babblesim_ext_libCryptov1
+      remote: babblesim
+      repo-path: ext_libCryptov1.git
+      path: tools/bsim/components/ext_libCryptov1
+      revision: eed6d7038e839153e340bd333bc43541cb90ba64
+      groups:
+        - babblesim
   self:
     west-commands: scripts/west-commands.yml
diff --git a/docs/blog/2020-10-03-bootloader-fix.md b/docs/blog/2020-10-03-bootloader-fix.md
index 435034cf..aceee490 100644
--- a/docs/blog/2020-10-03-bootloader-fix.md
+++ b/docs/blog/2020-10-03-bootloader-fix.md
@@ -176,7 +176,6 @@ this to all of the `.dts` files for the boards that were affected by this issue.
 
 ```diff
         code_partition: partition@26000 {
-            label = "code_partition";
 -           reg = <0x00026000 0x000d2000>;
 +           reg = <0x00026000 0x000c6000>;
         };
@@ -184,7 +183,6 @@ this to all of the `.dts` files for the boards that were affected by this issue.
 
 -       storage_partition: partition@f8000 {
 +       storage_partition: partition@ec000 {
-            label = "storage";
 -           reg = <0x000f8000 0x00008000>;
 +           reg = <0x000ec000 0x00008000>;
         };
@@ -193,3 +191,7 @@ this to all of the `.dts` files for the boards that were affected by this issue.
 And with those changes, we should no longer run into this issue! In the process
 of these changes, we lost 48KB of space for application code, but we're only
 using around 20% of it anyways. 🎉
+
+## Article Updates
+
+- 12/2023: Removed the deprecated `label` property from code snippets.
diff --git a/docs/blog/2021-01-27-zmk-sotf-4.md b/docs/blog/2021-01-27-zmk-sotf-4.md
index fbb53e40..823c4c5f 100644
--- a/docs/blog/2021-01-27-zmk-sotf-4.md
+++ b/docs/blog/2021-01-27-zmk-sotf-4.md
@@ -98,7 +98,7 @@ There has been lots of work to get display support complete enough for use by en
 
 #### Highest Layer Display
 
-[mcrosson] has contributed the next display widget, showing the highest active layer in the keymap. [petejohanson] then added a small follow up to allow layers in keymaps to add a `label` property to each layer, e.g. `label = "Nav";` and have that label be displayed in the widget instead of the numeric layer number.
+[mcrosson] has contributed the next display widget, showing the highest active layer in the keymap. [petejohanson] then added a small follow up to allow layers in keymaps to add a `name` property to each layer, e.g. `name = "Nav";` and have that name be displayed in the widget instead of the numeric layer number.
 
 #### WPM
 
@@ -192,3 +192,7 @@ Thanks again to the numerous contributors, testers, and users who have made work
 [petejohanson]: https://github.com/petejohanson
 [innovaker]: https://github.com/innovaker
 [joelspadin]: https://github.com/joelspadin
+
+## Article Updates
+
+- 12/2023: The `label` property for keymap layers was renamed to `display-name`.
diff --git a/docs/blog/2022-04-02-zephyr-3-0.md b/docs/blog/2022-04-02-zephyr-3-0.md
index 6ec4c904..3b16b87e 100644
--- a/docs/blog/2022-04-02-zephyr-3-0.md
+++ b/docs/blog/2022-04-02-zephyr-3-0.md
@@ -79,7 +79,6 @@ Zephyr's WS2812 `led_strip` driver added a new required property. When adding [u
 ```dts
 led_strip: ws2812@0 {
   compatible = "worldsemi,ws2812-spi";
-  label = "WS2812";
 
   /* SPI */
   reg = <0>; /* ignored, but necessary for SPI bindings */
@@ -115,7 +114,6 @@ For example, for a shield with:
   oled: ssd1306@3c {
     compatible = "solomon,ssd1306fb";
     reg = <0x3c>;
-    label = "SSD1306";
     width = <128>;
     height = <32>;
     segment-offset = <0>;
@@ -153,7 +151,6 @@ Underneath the USB device, add the CDC ACM node:
   status = "okay";
   cdc_acm_uart: cdc_acm_uart {
     compatible = "zephyr,cdc-acm-uart";
-    label = "CDC_ACM_0";
   };
 };
 ```
@@ -226,3 +223,7 @@ This will also enable us to support the XIAO compatible Adafruit Qt Py RP2040 an
 Thanks to all the testers who have helped verify ZMK functionality on the newer Zephyr version.
 
 [petejohanson]: https://github.com/petejohanson
+
+## Article Updates
+
+- 12/2023: Removed the deprecated `label` property from code snippets.
diff --git a/docs/blog/2022-04-10-zmk-sotf-5.md b/docs/blog/2022-04-10-zmk-sotf-5.md
index 4ea62a31..43cb4e67 100644
--- a/docs/blog/2022-04-10-zmk-sotf-5.md
+++ b/docs/blog/2022-04-10-zmk-sotf-5.md
@@ -55,7 +55,6 @@ a user taps a single key in their keymap, e.g.
     behaviors {
         td0: tap_dance_0 {
             compatible = "zmk,behavior-tap-dance";
-            label = "TAP_DANCE_0";
             #binding-cells = <0>;
             tapping-term-ms = <200>;
             bindings = <&kp N1>, <&kp N2>, <&kp N3>;
@@ -263,3 +262,7 @@ As we approach the two year birthday for ZMK, I am reminded of how far we have c
 [joelspadin]: https://github.com/joelspadin
 [bcat]: https://github.com/bcat
 [dxmh]: https://github.com/dxmh
+
+## Article Updates
+
+- 12/2023: Removed the deprecated `label` property from code snippets.
diff --git a/docs/blog/2023-06-18-encoder-refactors.md b/docs/blog/2023-06-18-encoder-refactors.md
index 14be81c8..db544d38 100644
--- a/docs/blog/2023-06-18-encoder-refactors.md
+++ b/docs/blog/2023-06-18-encoder-refactors.md
@@ -38,7 +38,6 @@ Previously, an encoder configuration looked like:
 ```dts
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         resolution = <4>;
@@ -61,7 +60,6 @@ That was the entirety of the configuration for encoders.
 ```dts
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -117,3 +115,7 @@ The old configuration will be supported for a period of one month, and then remo
 
 [petejohanson]: https://github.com/petejohanson
 [joelspadin]: https://github.com/joelspadin
+
+## Article Updates
+
+- 12/2023: Removed the deprecated `label` property from code snippets.
diff --git a/docs/blog/2023-10-05-zmk-sotf-6.md b/docs/blog/2023-10-05-zmk-sotf-6.md
index 5aa1567a..fb8dc131 100644
--- a/docs/blog/2023-10-05-zmk-sotf-6.md
+++ b/docs/blog/2023-10-05-zmk-sotf-6.md
@@ -34,7 +34,6 @@ As an example, you can now define a mod-morph that swaps `;` and `:` so that the
 ```dts
         col_semi: colon_semicolon {
             compatible = "zmk,behavior-mod-morph";
-            label = "COLON_SEMICOLON";
             #binding-cells = <0>;
             bindings = <&kp COLON>, <&kp SEMI>;
             mods = <(MOD_LSFT|MOD_RSFT)>;
@@ -48,9 +47,8 @@ As an example, you can now define a mod-morph that swaps `;` and `:` so that the
 As a simple example, you could define a macro that puts any keycode provided between double quotes as below, then use it like `&ql A` in your keymap:
 
 ```dts
-        ql: quoted_letter_macro {
+        ql: quoted_letter {
             #binding-cells = <1>;
-            label = "QUOTED_LETTER";
             compatible = "zmk,behavior-macro-one-param";
             bindings =
                 <&kp DQT>,
@@ -293,3 +291,7 @@ Also a big thank you to contributors that submit patches and perform reviews, te
 [urob]: https://github.com/urob
 [filterpaper]: https://github.com/filterpaper
 [ReFil]: https://github.com/ReFil
+
+## Article Updates
+
+- 12/2023: Removed the deprecated `label` property from code snippets.
diff --git a/docs/docs/behaviors/bluetooth.md b/docs/docs/behaviors/bluetooth.md
index 1d461722..b34614e6 100644
--- a/docs/docs/behaviors/bluetooth.md
+++ b/docs/docs/behaviors/bluetooth.md
@@ -13,6 +13,13 @@ computer/laptop/keyboard should receive the keyboard input; many of the commands
 When pairing to a host device ZMK saves bond information to the selected profile. It will not replace this when you initiate pairing with another device. To pair with a new device select an unused profile with `BT_SEL`, `BT_NXT` or `BT_PRV` bindings, or by clearing an existing profile using `BT_CLR`.
 
 A ZMK device may show as "connected" on multiple hosts at the same time. This is working as intended, and only the host associated with the active profile will receive keystrokes.
+
+An _inactive_ connected profile can be explicitly disconnected using the `BT_DISC` behavior. This can be helpful in
+cases when host devices behave differently when a bluetooth keyboard is connected, for example by hiding their on-screen
+keyboard. Note that at present the active bluetooth profile will immediately reconnect if disconnected. This is true
+even if OUT_USB is selected. To remain disconnected, another bluetooth profile must be first selected using (e.g.)
+`BT_SEL`.
+
 :::
 
 ## Bluetooth Command Defines
@@ -28,12 +35,13 @@ This will allow you to reference the actions defined in this header such as `BT_
 
 Here is a table describing the command for each define:
 
-| Define   | Action                                                                                                                                                    |
-| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `BT_CLR` | Clear bond information between the keyboard and host for the selected profile.                                                                            |
-| `BT_NXT` | Switch to the next profile, cycling through to the first one when the end is reached.                                                                     |
-| `BT_PRV` | Switch to the previous profile, cycling through to the last one when the beginning is reached.                                                            |
-| `BT_SEL` | Select the 0-indexed profile by number. Please note: this definition must include a number as an argument in the keymap to work correctly. eg. `BT_SEL 0` |
+| Define    | Action                                                                                                                                                                             |
+| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `BT_CLR`  | Clear bond information between the keyboard and host for the selected profile.                                                                                                     |
+| `BT_NXT`  | Switch to the next profile, cycling through to the first one when the end is reached.                                                                                              |
+| `BT_PRV`  | Switch to the previous profile, cycling through to the last one when the beginning is reached.                                                                                     |
+| `BT_SEL`  | Select the 0-indexed profile by number; must include a number as an argument in the keymap to work correctly, e.g. `BT_SEL 0`.                                                     |
+| `BT_DISC` | Disconnect from the 0-indexed profile by number, if it's currently connected and inactive; must include a number as an argument in the keymap to work correctly, e.g. `BT_DISC 0`. |
 
 :::note Selected profile persistence
 The profile that is selected by the `BT_SEL`/`BT_PRV`/`BT_NXT` actions will be saved to flash storage and hence persist across restarts and firmware flashes.
diff --git a/docs/docs/behaviors/caps-word.md b/docs/docs/behaviors/caps-word.md
index 0233de52..77c8fd20 100644
--- a/docs/docs/behaviors/caps-word.md
+++ b/docs/docs/behaviors/caps-word.md
@@ -59,9 +59,8 @@ If you want to use multiple caps breaks with different codes to break the caps,
 
 ```dts
 / {
-    prog_caps: behavior_prog_caps_word {
+    prog_caps: prog_caps {
         compatible = "zmk,behavior-caps-word";
-        label = "PROG_CAPS";
         #binding-cells = <0>;
         continue-list = <UNDERSCORE>;
     };
diff --git a/docs/docs/behaviors/hold-tap.md b/docs/docs/behaviors/hold-tap.md
index 96e03a0e..64fb9396 100644
--- a/docs/docs/behaviors/hold-tap.md
+++ b/docs/docs/behaviors/hold-tap.md
@@ -58,7 +58,6 @@ For example, the following hold-tap configuration enables `require-prior-idle-ms
 ```dts
 rpi: require_prior_idle {
     compatible = "zmk,behavior-hold-tap";
-    label = "REQUIRE_PRIOR_IDLE";
     #binding-cells = <2>;
     flavor = "tap-preferred";
     tapping-term-ms = <200>;
@@ -104,7 +103,6 @@ See the following example, which uses a hold-tap behavior definition, configured
     behaviors {
         pht: positional_hold_tap {
             compatible = "zmk,behavior-hold-tap";
-            label = "POSITIONAL_HOLD_TAP";
             #binding-cells = <2>;
             flavor = "hold-preferred";
             tapping-term-ms = <400>;
@@ -115,7 +113,6 @@ See the following example, which uses a hold-tap behavior definition, configured
     };
     keymap {
         compatible = "zmk,keymap";
-        label ="Default keymap";
         default_layer {
             bindings = <
                 //  position 0         position 1       position 2
@@ -172,9 +169,8 @@ The following are suggested hold-tap configurations that work well with home row
 
 / {
     behaviors {
-        lh_pht: left_hand_positional_hold_tap {
+        lh_pht: left_positional_hold_tap {
             compatible = "zmk,behavior-hold-tap";
-            label = "LEFT_POSITIONAL_HOLD_TAP";
             #binding-cells = <2>;
             flavor = "tap-unless-interrupted";
             tapping-term-ms = <100>;                        // <---[[produces tap if held longer than tapping-term-ms]]
@@ -206,7 +202,6 @@ The following are suggested hold-tap configurations that work well with home row
     behaviors {
         hm: homerow_mods {
             compatible = "zmk,behavior-hold-tap";
-            label = "HOMEROW_MODS";
             #binding-cells = <2>;
             tapping-term-ms = <150>;
             quick-tap-ms = <0>;
@@ -236,7 +231,6 @@ The following are suggested hold-tap configurations that work well with home row
     behaviors {
         bhm: balanced_homerow_mods {
             compatible = "zmk,behavior-hold-tap";
-            label = "HOMEROW_MODS";
             #binding-cells = <2>;
             tapping-term-ms = <200>;    // <---[[moderate duration]]
             quick-tap-ms = <0>;
@@ -272,7 +266,6 @@ A popular method of implementing Autoshift in ZMK involves a C-preprocessor macr
     behaviors {
         as: auto_shift {
             compatible = "zmk,behavior-hold-tap";
-            label = "AUTO_SHIFT";
             #binding-cells = <2>;
             tapping_term_ms = <135>;
             quick_tap_ms = <0>;
@@ -308,7 +301,6 @@ This hold-tap example implements a [momentary-layer](layers.md/#momentary-layer)
     behaviors {
         mo_tog: behavior_mo_tog {
             compatible = "zmk,behavior-hold-tap";
-            label = "mo_tog";
             #binding-cells = <2>;
             flavor = "hold-preferred";
             tapping-term-ms = <200>;
diff --git a/docs/docs/behaviors/macros.md b/docs/docs/behaviors/macros.md
index 7ce968e9..37ca80ff 100644
--- a/docs/docs/behaviors/macros.md
+++ b/docs/docs/behaviors/macros.md
@@ -18,7 +18,6 @@ A macro definition looks like:
 / {
     macros {
         zed_em_kay: zed_em_kay {
-            label = "ZM_zed_em_kay";
             compatible = "zmk,behavior-macro";
             #binding-cells = <0>;
             bindings
@@ -239,7 +238,6 @@ To achieve this, a combination of a 0ms wait time and splitting the press and re
  *  `&lm NUM_LAYER LSHIFT`
  */
 lm: lm {
-    label = "LAYER_MOD";
     compatible = "zmk,behavior-macro-two-param";
     wait-ms = <0>;
     tap-ms = <0>;
@@ -323,7 +321,6 @@ This can be used instead of a complete macro definition. During the firmware bui
 ```dts
     my_zero_param_macro: my_zero_param_macro {
         compatible = "zmk,behavior-macro";
-        label = "ZM_my_macro";
         #binding-cells = <0>;
         wait-ms = <30>;
         tap-ms = <40>;
diff --git a/docs/docs/behaviors/mod-morph.md b/docs/docs/behaviors/mod-morph.md
index 6099b428..d5b3d589 100644
--- a/docs/docs/behaviors/mod-morph.md
+++ b/docs/docs/behaviors/mod-morph.md
@@ -23,7 +23,6 @@ An example of how to implement the mod-morph "Grave Escape":
     behaviors {
         gresc: grave_escape {
             compatible = "zmk,behavior-mod-morph";
-            label = "GRAVE_ESCAPE";
             #binding-cells = <0>;
             bindings = <&kp ESC>, <&kp GRAVE>;
             mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>;
@@ -79,7 +78,6 @@ For example, the following configuration morphs `LEFT_SHIFT` + `BACKSPACE` into
     behaviors {
         bspc_del: backspace_delete {
             compatible = "zmk,behavior-mod-morph";
-            label = "BACKSPACE_DELETE";
             #binding-cells = <0>;
             bindings = <&kp BACKSPACE>, <&kp DELETE>;
             mods = <(MOD_LSFT|MOD_RSFT)>;
diff --git a/docs/docs/behaviors/sensor-rotate.md b/docs/docs/behaviors/sensor-rotate.md
index 3ff69dc6..f8476bae 100644
--- a/docs/docs/behaviors/sensor-rotate.md
+++ b/docs/docs/behaviors/sensor-rotate.md
@@ -24,7 +24,6 @@ Here is an example that binds the [RGB Underglow Behavior](/docs/behaviors/under
     behaviors {
         rgb_encoder: rgb_encoder {
             compatible = "zmk,behavior-sensor-rotate";
-            label = "RGB_ENCODER";
             #sensor-binding-cells = <0>;
             bindings = <&rgb_ug RGB_BRI>, <&rgb_ug RGB_BRD>;
         };
@@ -58,9 +57,8 @@ First, defining the sensor rotation itself, binding the [Key Press Behavior](/do
 ```dts
 / {
     behaviors {
-        rot_kp: behavior_sensor_rotate_kp {
+        rot_kp: sensor_rotate_kp {
             compatible = "zmk,behavior-sensor-rotate-var";
-            label = "ENC_KP";
             #sensor-binding-cells = <2>;
             bindings = <&kp>, <&kp>;
         };
diff --git a/docs/docs/behaviors/sticky-key.md b/docs/docs/behaviors/sticky-key.md
index 8b003f55..f40bb521 100644
--- a/docs/docs/behaviors/sticky-key.md
+++ b/docs/docs/behaviors/sticky-key.md
@@ -61,7 +61,6 @@ This configuration would apply to all sticky keys. This may not be appropriate i
     behaviors {
       skq: sticky_key_quick_release {
         compatible = "zmk,behavior-sticky-key";
-        label = "STICKY_KEY_QUICK_RELEASE";
         #binding-cells = <1>;
         bindings = <&kp>;
         release-after-ms = <1000>;
diff --git a/docs/docs/behaviors/tap-dance.md b/docs/docs/behaviors/tap-dance.md
index ac85b3da..1566cf18 100644
--- a/docs/docs/behaviors/tap-dance.md
+++ b/docs/docs/behaviors/tap-dance.md
@@ -45,7 +45,6 @@ This example configures a tap-dance named `td0` that outputs the number of times
     behaviors {
         td0: tap_dance_0 {
             compatible = "zmk,behavior-tap-dance";
-            label = "TAP_DANCE_0";
             #binding-cells = <0>;
             tapping-term-ms = <200>;
             bindings = <&kp N1>, <&kp N2>, <&kp N3>;
@@ -86,7 +85,6 @@ This example configures a mod-tap inside a tap-dance named `td_mt` that outputs
     behaviors {
         td_mt: tap_dance_mod_tap {
             compatible = "zmk,behavior-tap-dance";
-            label = "TAP_DANCE_MOD_TAP";
             #binding-cells = <0>;
             tapping-term-ms = <200>;
             bindings = <&mt LSHIFT CAPSLOCK>, <&kp LCTRL>;
diff --git a/docs/docs/config/battery.md b/docs/docs/config/battery.md
index 8d65a00a..50f16cfe 100644
--- a/docs/docs/config/battery.md
+++ b/docs/docs/config/battery.md
@@ -48,7 +48,7 @@ See [Zephyr's voltage divider documentation](https://docs.zephyrproject.org/late
 
 ## nRF VDDH Battery Sensor
 
-Driver for reading the voltage of a battery using a Nordic nRF52's VDDH pin. This driver has no configuration except for the required `label` property.
+Driver for reading the voltage of a battery using a Nordic nRF52's VDDH pin.
 
 ### Devicetree
 
@@ -56,6 +56,4 @@ Applies to: `compatible = "zmk,battery-nrf-vddh"`
 
 Definition file: [zmk/app/module/dts/bindings/sensor/zmk,battery-nrf-vddh.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/sensor/zmk%2Cbattery-nrf-vddh.yaml)
 
-| Property | Type   | Description               |
-| -------- | ------ | ------------------------- |
-| `label`  | string | Unique label for the node |
+This driver has no configuration.
diff --git a/docs/docs/config/behaviors.md b/docs/docs/config/behaviors.md
index f3f1f563..09498e6b 100644
--- a/docs/docs/config/behaviors.md
+++ b/docs/docs/config/behaviors.md
@@ -29,12 +29,11 @@ Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-caps-word.yaml](ht
 
 Applies to: `compatible = "zmk,behavior-caps-word"`
 
-| Property         | Type   | Description                                                        | Default                         |
-| ---------------- | ------ | ------------------------------------------------------------------ | ------------------------------- |
-| `label`          | string | Unique label for the node                                          |                                 |
-| `#binding-cells` | int    | Must be `<0>`                                                      |                                 |
-| `continue-list`  | array  | List of [key codes](/docs/codes) which do not deactivate caps lock | `<UNDERSCORE BACKSPACE DELETE>` |
-| `mods`           | int    | A bit field of modifiers to apply                                  | `<MOD_LSFT>`                    |
+| Property         | Type  | Description                                                        | Default                         |
+| ---------------- | ----- | ------------------------------------------------------------------ | ------------------------------- |
+| `#binding-cells` | int   | Must be `<0>`                                                      |                                 |
+| `continue-list`  | array | List of [key codes](/docs/codes) which do not deactivate caps lock | `<UNDERSCORE BACKSPACE DELETE>` |
+| `mods`           | int   | A bit field of modifiers to apply                                  | `<MOD_LSFT>`                    |
 
 `continue-list` is treated as if it always includes alphanumeric characters (A-Z, 0-9).
 
@@ -50,7 +49,7 @@ You can use the following nodes to tweak the default behaviors:
 
 Creates a custom behavior that triggers one behavior when a key is held or a different one when the key is tapped.
 
-See the [hold-tap behavior documentation](../behaviors/hold-tap.md) for more details and examples.
+See the [hold-tap behavior](../behaviors/hold-tap.md) documentation for more details and examples.
 
 ### Devicetree
 
@@ -60,7 +59,6 @@ Applies to: `compatible = "zmk,behavior-hold-tap"`
 
 | Property                     | Type          | Description                                                                                                    | Default            |
 | ---------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------- | ------------------ |
-| `label`                      | string        | Unique label for the node                                                                                      |                    |
 | `#binding-cells`             | int           | Must be `<2>`                                                                                                  |                    |
 | `bindings`                   | phandle array | A list of two behaviors (without parameters): one for hold and one for tap                                     |                    |
 | `flavor`                     | string        | Adjusts how the behavior chooses between hold and tap                                                          | `"hold-preferred"` |
@@ -70,6 +68,8 @@ Applies to: `compatible = "zmk,behavior-hold-tap"`
 | `retro-tap`                  | bool          | Triggers the tap behavior on release if no other key was pressed during a hold                                 | false              |
 | `hold-trigger-key-positions` | array         | If set, pressing the hold-tap and then any key position _not_ in the list triggers a tap.                      |                    |
 
+This behavior forwards the first parameter it receives to the parameter of the first behavior specified in `bindings`, and second parameter to the parameter of the second behavior.
+
 The `flavor` property may be one of:
 
 - `"hold-preferred"`
@@ -100,11 +100,10 @@ Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-key-repeat.yaml](h
 
 Applies to: `compatible = "zmk,behavior-key-repeat"`
 
-| Property         | Type   | Description                      | Default           |
-| ---------------- | ------ | -------------------------------- | ----------------- |
-| `label`          | string | Unique label for the node        |                   |
-| `#binding-cells` | int    | Must be `<0>`                    |                   |
-| `usage-pages`    | array  | List of HID usage pages to track | `<HID_USAGE_KEY>` |
+| Property         | Type  | Description                      | Default           |
+| ---------------- | ----- | -------------------------------- | ----------------- |
+| `#binding-cells` | int   | Must be `<0>`                    |                   |
+| `usage-pages`    | array | List of HID usage pages to track | `<HID_USAGE_KEY>` |
 
 For the `usage-pages` property, use the `HID_USAGE_*` defines from [dt-bindings/zmk/hid_usage_pages.h](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/hid_usage_pages.h).
 
@@ -129,16 +128,21 @@ See the [macro behavior](../behaviors/macros.md) documentation for more details
 
 ### Devicetree
 
-Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-macro.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-macro.yaml)
+Definition files:
 
-| Property         | Type          | Description                                                                                                                                  | Default                            |
-| ---------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
-| `label`          | string        | Unique label for the node                                                                                                                    |                                    |
-| `compatible`     | string        | Macro type, **must be _one_ of**:<br/>• `"zmk,behavior-macro"`<br/>• `"zmk,behavior-macro-one-param"`<br/>• `"zmk,behavior-macro-two-param"` |                                    |
-| `#binding-cells` | int           | Number of params accepted (depends on `compatible` property), **must be _one_ of**:<br/>• `<0>`<br/>• `<1>`<br/>• `<2>`                      |                                    |
-| `bindings`       | phandle array | List of behaviors to trigger                                                                                                                 |                                    |
-| `wait-ms`        | int           | The default time to wait (in milliseconds) before triggering the next behavior.                                                              | `CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS` |
-| `tap-ms`         | int           | The default time to wait (in milliseconds) between the press and release events of a tapped behavior.                                        | `CONFIG_ZMK_MACRO_DEFAULT_TAP_MS`  |
+- [zmk/app/dts/bindings/behaviors/zmk,behavior-macro.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-macro.yaml)
+- [zmk/app/dts/bindings/behaviors/zmk,behavior-macro-one-param.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-macro-one-param.yaml)
+- [zmk/app/dts/bindings/behaviors/zmk,behavior-macro-two-param.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-macro-two-param.yaml)
+
+| Property         | Type          | Description                                                                                                                                                                                          | Default                            |
+| ---------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
+| `compatible`     | string        | Macro type, **must be _one_ of**:<ul><li>`"zmk,behavior-macro"`</li><li>`"zmk,behavior-macro-one-param"`</li><li>`"zmk,behavior-macro-two-param"`</li></ul>                                          |                                    |
+| `#binding-cells` | int           | Must be <ul><li>`<0>` if `compatible = "zmk,behavior-macro"`</li><li>`<1>` if `compatible = "zmk,behavior-macro-one-param"`</li><li>`<2>` if `compatible = "zmk,behavior-macro-two-param"`</li></ul> |                                    |
+| `bindings`       | phandle array | List of behaviors to trigger                                                                                                                                                                         |                                    |
+| `wait-ms`        | int           | The default time to wait (in milliseconds) before triggering the next behavior.                                                                                                                      | `CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS` |
+| `tap-ms`         | int           | The default time to wait (in milliseconds) between the press and release events of a tapped behavior.                                                                                                | `CONFIG_ZMK_MACRO_DEFAULT_TAP_MS`  |
+
+With `compatible = "zmk,behavior-macro-one-param"` or `compatible = "zmk,behavior-macro-two-param"`, this behavior forwards the parameters it receives according to the `&macro_param_*` control behaviors noted below.
 
 ### Macro Control Behaviors
 
@@ -161,6 +165,8 @@ The following macro-specific behaviors can be added at any point in the `binding
 
 Creates a custom behavior that triggers one of two behaviors depending on whether certain modifiers are held.
 
+See the [mod-morph behavior](../behaviors/mod-morph.md) documentation for more details and examples.
+
 ### Devicetree
 
 Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-mod-morph.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-mod-morph.yaml)
@@ -169,7 +175,6 @@ Applies to: `compatible = "zmk,behavior-mod-morph"`
 
 | Property         | Type          | Description                                                                       |
 | ---------------- | ------------- | --------------------------------------------------------------------------------- |
-| `label`          | string        | Unique label for the node                                                         |
 | `#binding-cells` | int           | Must be `<0>`                                                                     |
 | `bindings`       | phandle array | A list of two behaviors: one for normal press and one for mod morphed press       |
 | `mods`           | int           | A bit field of modifiers. The morph behavior is used if any of these are pressed. |
@@ -182,6 +187,29 @@ You can use the following nodes to tweak the default behaviors:
 | -------- | ----------------------------------------- |
 | `&gresc` | [Grave escape](../behaviors/mod-morph.md) |
 
+## Sensor Rotation
+
+Creates a custom behavior which sends a tap of other behaviors when a sensor is rotated.
+Has two variants: with `compatible = "zmk,behavior-sensor-rotate"` it accepts no parameters when used, whereas with `compatible = "zmk,behavior-sensor-rotate-var"` it accepts two parameters.
+
+See the [sensor rotation behavior](../behaviors/sensor-rotate.md) documentation for more details and examples.
+
+### Devicetree
+
+Definition files:
+
+- [zmk/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-sensor-rotate.yaml)
+- [zmk/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-var.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-sensor-rotate-var.yaml)
+
+| Property                | Type          | Description                                                                                                                                                                        | Default |
+| ----------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
+| `compatible`            | string        | Sensor rotation type, **must be _one_ of**: <ul><li>`"zmk,behavior-sensor-rotate"`</li><li>`"zmk,behavior-sensor-rotate-var"`</li></ul>                                            |         |
+| `#sensor-binding-cells` | int           | Must be <ul><li>`<0>` if `compatible = "zmk,behavior-sensor-rotate"`</li><li>`<2>` if `compatible = "zmk,behavior-sensor-rotate-var"`</li></ul>                                    |         |
+| `bindings`              | phandle array | A list of two behaviors to trigger for each rotation direction, must include parameters for `"zmk,behavior-sensor-rotate"` and exclude them for `"zmk,behavior-sensor-rotate-var"` |         |
+| `tap-ms`                | int           | The tap duration (between press and release events) in milliseconds for behaviors in `bindings`                                                                                    | 5       |
+
+With `compatible = "zmk,behavior-sensor-rotate-var"`, this behavior forwards the first parameter it receives to the parameter of the first behavior specified in `bindings`, and second parameter to the parameter of the second behavior.
+
 ## Sticky Key
 
 Creates a custom behavior that triggers a behavior and keeps it pressed it until another key is pressed and released.
@@ -196,13 +224,14 @@ Applies to: `compatible = "zmk,behavior-sticky-key"`
 
 | Property           | Type          | Description                                                              | Default |
 | ------------------ | ------------- | ------------------------------------------------------------------------ | ------- |
-| `label`            | string        | Unique label for the node                                                |         |
-| `#binding-cells`   | int           | Must match the number of parameters the `bindings` behavior uses         |         |
+| `#binding-cells`   | int           | Must be `<1>`                                                            |         |
 | `bindings`         | phandle array | A behavior (without parameters) to trigger                               |         |
 | `release-after-ms` | int           | Releases the key after this many milliseconds if no other key is pressed | 1000    |
 | `quick-release`    | bool          | Release the sticky key on the next key press instead of release          | false   |
 | `ignore-modifiers` | bool          | If enabled, pressing a modifier key does not cancel the sticky key       | true    |
 
+This behavior forwards the one parameter it receives to the parameter of the behavior specified in `bindings`.
+
 You can use the following nodes to tweak the default behaviors:
 
 | Node  | Behavior                                     |
@@ -214,6 +243,8 @@ You can use the following nodes to tweak the default behaviors:
 
 Creates a custom behavior that triggers a different behavior corresponding to the number of times the key is tapped.
 
+See the [tap dance behavior](../behaviors/tap-dance.md) documentation for more details and examples.
+
 ### Devicetree
 
 Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-tap-dance.yaml)
@@ -222,7 +253,6 @@ Applies to: `compatible = "zmk,behavior-tap-dance"`
 
 | Property          | Type          | Description                                                                                  | Default |
 | ----------------- | ------------- | -------------------------------------------------------------------------------------------- | ------- |
-| `label`           | string        | Unique label for the node                                                                    |         |
 | `#binding-cells`  | int           | Must be `<0>`                                                                                |         |
 | `bindings`        | phandle array | A list of behaviors from which to select                                                     |         |
 | `tapping-term-ms` | int           | The maximum time (in milliseconds) between taps before an item from `bindings` is triggered. | 200     |
diff --git a/docs/docs/config/bluetooth.md b/docs/docs/config/bluetooth.md
index d2ddefdd..61477cb5 100644
--- a/docs/docs/config/bluetooth.md
+++ b/docs/docs/config/bluetooth.md
@@ -9,7 +9,8 @@ See [Configuration Overview](index.md) for instructions on how to change these s
 
 ## Kconfig
 
-| Option                                | Type | Description                                                                                                                                  | Default |
-| ------------------------------------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
-| `CONFIG_ZMK_BLE_PASSKEY_ENTRY`        | bool | Enable passkey entry during pairing for enhanced security. (Note: After enabling this, you will need to re-pair all previously paired hosts) | n       |
-| `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION` | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications.                      | y       |
+| Option                                 | Type | Description                                                                                                                                                                                                                                                                                                                        | Default |
+| -------------------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
+| `CONFIG_ZMK_BLE_EXPERIMENTAL_FEATURES` | bool | Enables a combination of settings that are planned to be default in future versions of ZMK. This includes changes to timing on BLE pairing initation, BT Secure Connection passkey entry, restores use of the updated/new LLCP implementation, disables 2M PHY support, and allows overwrite of keys from previously paired hosts. | n       |
+| `CONFIG_ZMK_BLE_PASSKEY_ENTRY`         | bool | Enable passkey entry during pairing for enhanced security. (Note: After enabling this, you will need to re-pair all previously paired hosts)                                                                                                                                                                                       | n       |
+| `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION`  | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications.                                                                                                                                                                                                            | y       |
diff --git a/docs/docs/config/encoders.md b/docs/docs/config/encoders.md
index 3044b392..b242f49b 100644
--- a/docs/docs/config/encoders.md
+++ b/docs/docs/config/encoders.md
@@ -77,7 +77,6 @@ Definition file: [zmk/app/module/dts/bindings/sensor/alps,ec11.yaml](https://git
 
 | Property  | Type       | Description                                    | Default |
 | --------- | ---------- | ---------------------------------------------- | ------- |
-| `label`   | string     | Unique label for the node                      |         |
 | `a-gpios` | GPIO array | GPIO connected to the encoder's A pin          |         |
 | `b-gpios` | GPIO array | GPIO connected to the encoder's B pin          |         |
 | `steps`   | int        | Number of encoder pulses per complete rotation |         |
diff --git a/docs/docs/config/index.md b/docs/docs/config/index.md
index 3d7aeb48..d8a2aecf 100644
--- a/docs/docs/config/index.md
+++ b/docs/docs/config/index.md
@@ -122,7 +122,6 @@ Devicetree files look like this:
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
     };
 };
 ```
diff --git a/docs/docs/config/keymap.md b/docs/docs/config/keymap.md
index b4e81f5e..49924389 100644
--- a/docs/docs/config/keymap.md
+++ b/docs/docs/config/keymap.md
@@ -19,7 +19,7 @@ Each child node can have the following properties:
 
 | Property          | Type          | Description                                                            |
 | ----------------- | ------------- | ---------------------------------------------------------------------- |
-| `label`           | string        | Unique label for the node                                              |
+| `display-name`    | string        | Name for the layer on displays                                         |
 | `bindings`        | phandle-array | List of [key behaviors](../features/keymaps.md#behaviors), one per key |
 | `sensor-bindings` | phandle-array | List of sensor behaviors, one per sensor                               |
 
diff --git a/docs/docs/config/kscan.md b/docs/docs/config/kscan.md
index 00360c46..65ea63ec 100644
--- a/docs/docs/config/kscan.md
+++ b/docs/docs/config/kscan.md
@@ -48,7 +48,6 @@ Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-demux.yaml](h
 
 | Property                | Type       | Description                      | Default |
 | ----------------------- | ---------- | -------------------------------- | ------- |
-| `label`                 | string     | Unique label for the node        |         |
 | `input-gpios`           | GPIO array | Input GPIOs                      |         |
 | `output-gpios`          | GPIO array | Demultiplexer address GPIOs      |         |
 | `debounce-period`       | int        | Debounce period in milliseconds  | 5       |
@@ -74,7 +73,6 @@ Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml](
 
 | Property                  | Type       | Description                                                                                                 | Default |
 | ------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ------- |
-| `label`                   | string     | Unique label for the node                                                                                   |         |
 | `input-gpios`             | GPIO array | Input GPIOs (one per key)                                                                                   |         |
 | `debounce-press-ms`       | int        | Debounce time for key press in milliseconds. Use 0 for eager debouncing.                                    | 5       |
 | `debounce-release-ms`     | int        | Debounce time for key release in milliseconds.                                                              | 5       |
@@ -118,7 +116,6 @@ Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml](
 
 | Property                  | Type       | Description                                                                                                 | Default     |
 | ------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ----------- |
-| `label`                   | string     | Unique label for the node                                                                                   |             |
 | `row-gpios`               | GPIO array | Matrix row GPIOs in order, starting from the top row                                                        |             |
 | `col-gpios`               | GPIO array | Matrix column GPIOs in order, starting from the leftmost row                                                |             |
 | `debounce-press-ms`       | int        | Debounce time for key press in milliseconds. Use 0 for eager debouncing.                                    | 5           |
@@ -152,6 +149,39 @@ The output pins (e.g. columns for `col2row`) should have the flag `GPIO_ACTIVE_H
     };
 ```
 
+## Charlieplex Driver
+
+Keyboard scan driver where keys are arranged on a matrix with each GPIO used as both input and output.
+
+- With `interrupt-gpios` unset, this allows n pins to drive n\*(n-1) keys.
+- With `interrupt-gpios` set, n pins will drive (n-1)\*(n-2) keys, but provide much improved power handling.
+
+Definition file: [zmk/app/module/drivers/kscan/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/module/drivers/kscan/Kconfig)
+
+| Config                                              | Type        | Description                                                               | Default |
+| --------------------------------------------------- | ----------- | ------------------------------------------------------------------------- | ------- |
+| `CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BEFORE_INPUTS`   | int (ticks) | How long to wait before reading input pins after setting output active    | 0       |
+| `CONFIG_ZMK_KSCAN_CHARLIEPLEX_WAIT_BETWEEN_OUTPUTS` | int (ticks) | How long to wait between each output to allow previous output to "settle" | 0       |
+
+### Devicetree
+
+Applies to: `compatible = "zmk,kscan-gpio-charlieplex"`
+
+Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-charlieplex.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/kscan/zmk%2Ckscan-gpio-charlieplex.yaml)
+
+| Property                  | Type       | Description                                                                                 | Default |
+| ------------------------- | ---------- | ------------------------------------------------------------------------------------------- | ------- |
+| `gpios`                   | GPIO array | GPIOs used, listed in order.                                                                |         |
+| `interrupt-gpios`         | GPIO array | A single GPIO to use for interrupt. Leaving this empty will enable continuous polling.      |         |
+| `debounce-press-ms`       | int        | Debounce time for key press in milliseconds. Use 0 for eager debouncing.                    | 5       |
+| `debounce-release-ms`     | int        | Debounce time for key release in milliseconds.                                              | 5       |
+| `debounce-scan-period-ms` | int        | Time between reads in milliseconds when any key is pressed.                                 | 1       |
+| `poll-period-ms`          | int        | Time between reads in milliseconds when no key is pressed and `interrupt-gpois` is not set. | 10      |
+
+Define the transform with a [matrix transform](#matrix-transform). The row is always the driven pin, and the column always the receiving pin (input to the controller).
+For example, in `RC(5,0)` power flows from the 6th pin in `gpios` to the 1st pin in `gpios`.
+Exclude all positions where the row and column are the same as these pairs will never be triggered, since no pin can be both input and output at the same time.
+
 ## Composite Driver
 
 Keyboard scan driver which combines multiple other keyboard scan drivers.
@@ -162,17 +192,15 @@ Applies to : `compatible = "zmk,kscan-composite"`
 
 Definition file: [zmk/app/dts/bindings/zmk,kscan-composite.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk,kscan-composite.yaml)
 
-| Property | Type   | Description                                   | Default |
-| -------- | ------ | --------------------------------------------- | ------- |
-| `label`  | string | Unique label for the node                     |         |
-| `rows`   | int    | The number of rows in the composite matrix    |         |
-| `cols`   | int    | The number of columns in the composite matrix |         |
+| Property | Type | Description                                   | Default |
+| -------- | ---- | --------------------------------------------- | ------- |
+| `rows`   | int  | The number of rows in the composite matrix    |         |
+| `cols`   | int  | The number of columns in the composite matrix |         |
 
 The `zmk,kscan-composite` node should have one child node per keyboard scan driver that should be composited. Each child node can have the following properties:
 
 | Property        | Type    | Description                                                                    | Default |
 | --------------- | ------- | ------------------------------------------------------------------------------ | ------- |
-| `label`         | string  | Unique label for the node                                                      |         |
 | `kscan`         | phandle | Label of the kscan driver to include                                           |         |
 | `row-offset`    | int     | Shifts row 0 of the included driver to a new row in the composite matrix       | 0       |
 | `column-offset` | int     | Shifts column 0 of the included driver to a new column in the composite matrix | 0       |
@@ -237,7 +265,6 @@ One possible way to do this is a 3x4 matrix where the direct GPIO keys are shift
 
     kscan0: kscan_composite {
         compatible = "zmk,kscan-composite";
-        label = "KSCAN0";
         rows = <4>;
         columns = <3>;
 
@@ -275,14 +302,13 @@ Applies to: `compatible = "zmk,kscan-mock"`
 
 Definition file: [zmk/app/dts/bindings/zmk,kscan-mock.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk%2Ckscan-mock.yaml)
 
-| Property       | Type   | Description                                   | Default |
-| -------------- | ------ | --------------------------------------------- | ------- |
-| `label`        | string | Unique label for the node                     |         |
-| `event-period` | int    | Milliseconds between each generated event     |         |
-| `events`       | array  | List of key events to simulate                |         |
-| `rows`         | int    | The number of rows in the composite matrix    |         |
-| `cols`         | int    | The number of columns in the composite matrix |         |
-| `exit-after`   | bool   | Exit the program after running all events     | false   |
+| Property       | Type  | Description                                   | Default |
+| -------------- | ----- | --------------------------------------------- | ------- |
+| `event-period` | int   | Milliseconds between each generated event     |         |
+| `events`       | array | List of key events to simulate                |         |
+| `rows`         | int   | The number of rows in the composite matrix    |         |
+| `cols`         | int   | The number of columns in the composite matrix |         |
+| `exit-after`   | bool  | Exit the program after running all events     | false   |
 
 The `events` array should be defined using the macros from [app/module/include/dt-bindings/zmk/kscan_mock.h](https://github.com/zmkfirmware/zmk/blob/main/app/module/include/dt-bindings/zmk/kscan_mock.h).
 
@@ -400,12 +426,53 @@ Consider a keyboard with a [duplex matrix](https://wiki.ai03.com/books/pcb-desig
         // Shift  Z  X  C ...
         // Ctrl Alt       ...
         map = <
-            RC(0,0) RC(1,0) RC(0,1) RC(1,1)      // ...
-            RC(2,0) RC(3,0) RC(2,1) RC(3,1)      // ...
-            RC(4,0)   RC(5,0) RC(4,1) RC(5,1)    // ...
-            RC(6,0)      RC(7,0) RC(6,1) RC(7,1) // ...
-            RC(8,0)         RC(8,1) RC(9,1)      // ...
-            RC(10,0) RC(11,0)                    // ...
+            RC(0,0) RC(1,0) RC(0,1) RC(1,1)       // ...
+            RC(2,0) RC(3,0) RC(2,1) RC(3,1)       // ...
+            RC(4,0)   RC(5,0) RC(4,1) RC(5,1)     // ...
+            RC(6,0)     RC(7,0) RC(6,1) RC(7,1)   // ...
+            RC(8,0)       RC(9,0) RC(8,1) RC(9,1) // ...
+            RC(10,0) RC(11,0)                     // ...
+        >;
+    };
+};
+```
+
+### Example: Charlieplex
+
+Since a charlieplex driver will never align with a keyboard directly due to the un-addressable positions, a matrix transform should be used to map the pairs to the layout of the keys.
+Note that the entire addressable space does not need to be mapped.
+
+```devicetree
+/ {
+    chosen {
+        zmk,kscan = &kscan0;
+        zmk,matrix_transform = &default_transform;
+    };
+
+    kscan0: kscan {
+        compatible = "zmk,kscan-gpio-charlieplex";
+
+        interrupt-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) >;
+        gpios
+          = <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) >
+          , <&pro_micro 17 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) >
+          , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) >
+          , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) >
+          , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN) >
+          ; // addressable space is 5x5, (minus paired values)
+    };
+
+    default_transform: matrix_transform {
+        compatible = "zmk,matrix-transform";
+        rows = <3>;
+        columns = <5>;
+        //  Q  W  E  R
+        //   A  S  D  F
+        //    Z  X  C  V
+        map = <
+            RC(0,1) RC(0,2) RC(0,3) RC(0,4)
+              RC(1,0) RC(1,2) RC(1,3) RC(1,4)
+                RC(2,0) RC(2,1) RC(2,3) RC(2,4)
         >;
     };
 };
diff --git a/docs/docs/config/power.md b/docs/docs/config/power.md
index e09045ed..75e1b26a 100644
--- a/docs/docs/config/power.md
+++ b/docs/docs/config/power.md
@@ -42,6 +42,5 @@ Applies to: `compatible = "zmk,ext-power-generic"`
 
 | Property        | Type       | Description                                                   |
 | --------------- | ---------- | ------------------------------------------------------------- |
-| `label`         | string     | Unique label for the node                                     |
 | `control-gpios` | GPIO array | List of GPIOs which should be active to enable external power |
 | `init-delay-ms` | int        | number of milliseconds to delay after initializing the driver |
diff --git a/docs/docs/config/system.md b/docs/docs/config/system.md
index b9dd580d..4629ea0f 100644
--- a/docs/docs/config/system.md
+++ b/docs/docs/config/system.md
@@ -22,9 +22,10 @@ Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/
 
 ### HID
 
-| Config                                | Type | Description                                       | Default |
-| ------------------------------------- | ---- | ------------------------------------------------- | ------- |
-| `CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE` | int  | Number of consumer keys simultaneously reportable | 6       |
+| Config                                | Type | Description                                                    | Default |
+| ------------------------------------- | ---- | -------------------------------------------------------------- | ------- |
+| `CONFIG_ZMK_HID_INDICATORS`           | bool | Enable reciept of HID/LED indicator state from connected hosts | n       |
+| `CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE` | int  | Number of consumer keys simultaneously reportable              | 6       |
 
 Exactly zero or one of the following options may be set to `y`. The first is used if none are set.
 
@@ -33,12 +34,24 @@ Exactly zero or one of the following options may be set to `y`. The first is use
 | `CONFIG_ZMK_HID_REPORT_TYPE_HKRO` | Enable `CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE` key roll over.                                           |
 | `CONFIG_ZMK_HID_REPORT_TYPE_NKRO` | Enable full N-key roll over. This may prevent the keyboard from working with some BIOS/UEFI versions. |
 
+:::note NKRO usages
+
+By default the NKRO max usage is set so as to maximize compatibility, however certain less frequently used keys (F13-F24 and INTL1-8) will not work with it. One solution is to set `CONFIG_ZMK_HID_KEYBOARD_NKRO_EXTENDED_REPORT=y`, however this is known to break compatibility with Android and thus not enabled by default.
+
+:::
+
 If `CONFIG_ZMK_HID_REPORT_TYPE_HKRO` is enabled, it may be configured with the following options:
 
 | Config                                | Type | Description                                       | Default |
 | ------------------------------------- | ---- | ------------------------------------------------- | ------- |
 | `CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE` | int  | Number of keyboard keys simultaneously reportable | 6       |
 
+If `CONFIG_ZMK_HID_REPORT_TYPE_NKRO` is enabled, it may be configured with the following options:
+
+| Config                                         | Type | Description                                                          | Default |
+| ---------------------------------------------- | ---- | -------------------------------------------------------------------- | ------- |
+| `CONFIG_ZMK_HID_KEYBOARD_NKRO_EXTENDED_REPORT` | bool | Enable less frequently used key usages, at the cost of compatibility | n       |
+
 Exactly zero or one of the following options may be set to `y`. The first is used if none are set.
 
 | Config                                        | Description                                                                          |
@@ -91,14 +104,15 @@ Note that `CONFIG_BT_MAX_CONN` and `CONFIG_BT_MAX_PAIRED` should be set to the s
 
 Following split keyboard settings are defined in [zmk/app/src/split/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/Kconfig) (generic) and [zmk/app/src/split/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/bluetooth/Kconfig) (bluetooth).
 
-| Config                                                | Type | Description                                                             | Default |
-| ----------------------------------------------------- | ---- | ----------------------------------------------------------------------- | ------- |
-| `CONFIG_ZMK_SPLIT`                                    | bool | Enable split keyboard support                                           | n       |
-| `CONFIG_ZMK_SPLIT_BLE`                                | bool | Use BLE to communicate between split keyboard halves                    | y       |
-| `CONFIG_ZMK_SPLIT_ROLE_CENTRAL`                       | bool | `y` for central device, `n` for peripheral                              |         |
-| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE`    | int  | Max number of key state events to queue when received from peripherals  | 5       |
-| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_STACK_SIZE`   | int  | Stack size of the BLE split central write thread                        | 512     |
-| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_QUEUE_SIZE`   | int  | Max number of behavior run events to queue to send to the peripheral(s) | 5       |
-| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE`          | int  | Stack size of the BLE split peripheral notify thread                    | 650     |
-| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY`            | int  | Priority of the BLE split peripheral notify thread                      | 5       |
-| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE` | int  | Max number of key state events to queue to send to the central          | 10      |
+| Config                                                | Type | Description                                                              | Default |
+| ----------------------------------------------------- | ---- | ------------------------------------------------------------------------ | ------- |
+| `CONFIG_ZMK_SPLIT`                                    | bool | Enable split keyboard support                                            | n       |
+| `CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS`          | bool | Enable split keyboard support for passing indicator state to peripherals | n       |
+| `CONFIG_ZMK_SPLIT_BLE`                                | bool | Use BLE to communicate between split keyboard halves                     | y       |
+| `CONFIG_ZMK_SPLIT_ROLE_CENTRAL`                       | bool | `y` for central device, `n` for peripheral                               |         |
+| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE`    | int  | Max number of key state events to queue when received from peripherals   | 5       |
+| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_STACK_SIZE`   | int  | Stack size of the BLE split central write thread                         | 512     |
+| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_QUEUE_SIZE`   | int  | Max number of behavior run events to queue to send to the peripheral(s)  | 5       |
+| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE`          | int  | Stack size of the BLE split peripheral notify thread                     | 650     |
+| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY`            | int  | Priority of the BLE split peripheral notify thread                       | 5       |
+| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE` | int  | Max number of key state events to queue to send to the central           | 10      |
diff --git a/docs/docs/development/build-flash.md b/docs/docs/development/build-flash.md
index 0243983c..1699ac5c 100644
--- a/docs/docs/development/build-flash.md
+++ b/docs/docs/development/build-flash.md
@@ -92,6 +92,22 @@ This produces `left` and `right` subfolders under the `build` directory and two
 Build times can be significantly reduced after the initial build by omitting all build arguments except the build directory, e.g. `west build -d build/left`. The additional options and intermediate build outputs from your initial build are cached and reused for unchanged files.
 :::
 
+### Building with external modules
+
+ZMK supports loading additional boards, shields, code, etc. from [external Zephyr modules](https://docs.zephyrproject.org/3.2.0/develop/modules.html), facilitating out-of-tree management and versioning independent of the ZMK repository. To build with any additional modules, use the `ZMK_EXTRA_MODULES` define added to your `west build` command.
+
+For instance, building with the `my-vendor-keebs-module` checked out to your documents directory, you would build like:
+
+```
+west build -b nice_nano_v2 -- -DSHIELD=vendor_shield -DZMK_EXTRA_MODULES="C:/Users/myUser/Documents/my-vendor-keebs-module"
+```
+
+When adding multiple modules, make sure they are separated by a semicolon, e.g.:
+
+```
+west build -b nice_nano_v2 -- -DSHIELD=vendor_shield -DZMK_EXTRA_MODULES="C:/Users/myUser/Documents/my-vendor-keebs-module;C:/Users/myUser/Documents/my-other-keebs-module"
+```
+
 ### Building from `zmk-config` Folder
 
 Instead of building .uf2 files using the default keymap and config files, you can build directly from your [`zmk-config` folder](../user-setup.md#github-repo) by adding
diff --git a/docs/docs/development/new-behavior.md b/docs/docs/development/new-behavior.md
index aab056c1..59872963 100644
--- a/docs/docs/development/new-behavior.md
+++ b/docs/docs/development/new-behavior.md
@@ -171,12 +171,12 @@ static const struct behavior_driver_api <behavior_name>_driver_api = {
 
 };
 
-DEVICE_DT_INST_DEFINE(0,                                                    // Instance Number (Equal to 0 for behaviors that don't require multiple instances,
-                                                                            //                  Equal to n for behaviors that do make use of multiple instances)
-                      <behavior_name>_init, NULL,                           // Initialization Function, Power Management Device Pointer
-                      &<behavior_name>_data, &<behavior_name>_config,       // Behavior Data Pointer, Behavior Configuration Pointer (Both Optional)
-                      APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,     // Initialization Level, Device Priority
-                      &<behavior_name>_driver_api);                         // API Structure
+BEHAVIOR_DT_INST_DEFINE(0,                                                    // Instance Number (Equal to 0 for behaviors that don't require multiple instances,
+                                                                              //                  Equal to n for behaviors that do make use of multiple instances)
+                        <behavior_name>_init, NULL,                           // Initialization Function, Power Management Device Pointer
+                        &<behavior_name>_data, &<behavior_name>_config,       // Behavior Data Pointer, Behavior Configuration Pointer (Both Optional)
+                        APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,     // Initialization Level, Device Priority
+                        &<behavior_name>_driver_api);                         // API Structure
 
 #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
 
@@ -244,13 +244,15 @@ Listeners, defined by the `ZMK_LISTENER(mod, cb)` function, take in a listener n
 - `ZMK_EVENT_RELEASE(ev)`: Continue handling this event (`ev`) at the next registered event listener.
 - `ZMK_EVENT_FREE(ev)`: Free the memory associated with the event (`ev`).
 
-#### `DEVICE_DT_INST_DEFINE`
+#### `BEHAVIOR_DT_INST_DEFINE`
+
+`BEHAVIOR_DT_INST_DEFINE` is a special ZMK macro. It forwards all the parameters to Zephyr's `DEVICE_DT_INST_DEFINE` macro to define the driver instance, then it adds the driver to a list of ZMK behaviors so they can be found by `zmk_behavior_get_binding()`.
 
 :::info
 For more information on this function, refer to [Zephyr's documentation on the Device Driver Model](https://docs.zephyrproject.org/latest/kernel/drivers/index.html#c.DEVICE_DT_INST_DEFINE).
 :::
 
-The example `DEVICE_DT_INST_DEFINE` call can be left as is with the first parameter, the instance number, equal to `0` for behaviors that only require a single instance (e.g. external power, backlighting, accessing layers). For behaviors that can have multiple instances (e.g. hold-taps, tap-dances, sticky-keys), `DEVICE_DT_INST_DEFINE` can be placed inside a `#define` statement, usually formatted as `#define <ABBREVIATED BEHAVIOR NAME>_INST(n)`, that sets up any [data pointers](#data-pointers-optional) and/or [configuration pointers](#configuration-pointers-optional) that are unique to each instance.
+The example `BEHAVIOR_DT_INST_DEFINE` call can be left as is with the first parameter, the instance number, equal to `0` for behaviors that only require a single instance (e.g. external power, backlighting, accessing layers). For behaviors that can have multiple instances (e.g. hold-taps, tap-dances, sticky-keys), `BEHAVIOR_DT_INST_DEFINE` can be placed inside a `#define` statement, usually formatted as `#define <ABBREVIATED BEHAVIOR NAME>_INST(n)`, that sets up any [data pointers](#data-pointers-optional) and/or [configuration pointers](#configuration-pointers-optional) that are unique to each instance.
 
 An example of this can be seen below, taking the `#define KP_INST(n)` from the hold-tap driver.
 
@@ -266,16 +268,16 @@ An example of this can be seen below, taking the `#define KP_INST(n)` from the h
         .hold_trigger_key_positions = DT_INST_PROP(n, hold_trigger_key_positions),                 \
         .hold_trigger_key_positions_len = DT_INST_PROP_LEN(n, hold_trigger_key_positions),         \
     };                                                                                             \
-    DEVICE_DT_INST_DEFINE(n, behavior_hold_tap_init, NULL, NULL, &behavior_hold_tap_config_##n,    \
-                          APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                        \
-                          &behavior_hold_tap_driver_api);
+    BEHAVIOR_DT_INST_DEFINE(n, behavior_hold_tap_init, NULL, NULL, &behavior_hold_tap_config_##n,    \
+                            APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,                        \
+                            &behavior_hold_tap_driver_api);
 
 DT_INST_FOREACH_STATUS_OKAY(KP_INST)
 ```
 
 Note that in the hold-tap example, the instance number, `0`, has been replaced by `n`, signifying the unique `node_id` of each instance of a behavior. Furthermore, the DT_INST_FOREACH_STATUS_OKAY(KP_INST) macro iterates through each compatible, non-disabled devicetree node, creating and applying the proper values to any instance-specific configurations or data by invoking the KP_INST macro for each instance of the new behavior.
 
-Behaviors also require the following parameters of `DEVICE_DT_INST_DEFINE` to be changed:
+Behaviors also require the following parameters of `BEHAVIOR_DT_INST_DEFINE` to be changed:
 
 ##### Initialization Function
 
@@ -300,19 +302,19 @@ Comes in the form `static const struct behavior_driver_api <behavior_name>_drive
 The data `struct` stores additional data required for **each new instance** of the behavior. Regardless of the instance number, `n`, `behavior_<behavior_name>_data_##n` is typically initialized as an empty `struct`. The data respective to each instance of the behavior can be accessed in functions like [`on_<behavior_name>_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event)`](#dependencies) by extracting the behavior device from the keybind like so:
 
 ```c
-const struct device *dev = device_get_binding(binding->behavior_dev);
+const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
 struct behavior_<behavior_name>_data *data = dev->data;
 ```
 
 The variables stored inside the data `struct`, `data`, can be then modified as necessary.
 
-The fourth cell of `DEVICE_DT_INST_DEFINE` can be set to `NULL` instead if instance-specific data is not required.
+The fourth cell of `BEHAVIOR_DT_INST_DEFINE` can be set to `NULL` instead if instance-specific data is not required.
 
 ##### Configuration Pointers (Optional)
 
-The configuration `struct` stores the properties declared from the behavior's `.yaml` for **each new instance** of the behavior. As seen in the `#define KP_INST(n)` of the hold-tap example, the configuration `struct`, `behavior_<behavior_name>_config_##n`, for each instance number, `n`, can be initialized using the [Zephyr Devicetree Instance-based APIs](https://docs.zephyrproject.org/latest/build/dts/api/api.html#instance-based-apis), which extract the values from the `properties` of each instance of the [devicetree binding](#creating-the-devicetree-binding-yaml) from a user's keymap or [predefined use-case `.dtsi` files](#defining-common-use-cases-for-the-behavior-dtsi-optional) stored in `app/dts/behaviors/`. We illustrate this further by comparing the [`#define KP_INST(n)` from the hold-tap driver](#device_dt_inst_define) and the [`properties` of the hold-tap devicetree binding.](#creating-the-devicetree-binding-yaml)
+The configuration `struct` stores the properties declared from the behavior's `.yaml` for **each new instance** of the behavior. As seen in the `#define KP_INST(n)` of the hold-tap example, the configuration `struct`, `behavior_<behavior_name>_config_##n`, for each instance number, `n`, can be initialized using the [Zephyr Devicetree Instance-based APIs](https://docs.zephyrproject.org/latest/build/dts/api/api.html#instance-based-apis), which extract the values from the `properties` of each instance of the [devicetree binding](#creating-the-devicetree-binding-yaml) from a user's keymap or [predefined use-case `.dtsi` files](#defining-common-use-cases-for-the-behavior-dtsi-optional) stored in `app/dts/behaviors/`. We illustrate this further by comparing the [`#define KP_INST(n)` from the hold-tap driver](#behavior_dt_inst_define) and the [`properties` of the hold-tap devicetree binding.](#creating-the-devicetree-binding-yaml)
 
-The fifth cell of `DEVICE_DT_INST_DEFINE` can be set to `NULL` instead if instance-specific configurations are not required.
+The fifth cell of `BEHAVIOR_DT_INST_DEFINE` can be set to `NULL` instead if instance-specific configurations are not required.
 
 :::caution
 Remember that `.c` files should be formatted according to `clang-format` to ensure that checks run smoothly once the pull request is submitted.
@@ -370,7 +372,6 @@ For the purpose of this section, we will discuss the structure of `app/dts/behav
     behaviors {
         /omit-if-no-ref/ gresc: grave_escape {
             compatible = "zmk,behavior-mod-morph";
-            label = "GRAVE_ESCAPE";
             #binding-cells = <0>;
             bindings = <&kp ESC>, <&kp GRAVE>;
             mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>;
@@ -379,7 +380,20 @@ For the purpose of this section, we will discuss the structure of `app/dts/behav
 };
 ```
 
-The format of a behavior's `.dtsi` file is identical to declaring an instance of the behavior in a user's keymap. The only major difference is that the value `/omit-if-no-ref/` should be placed adjacent to the name of the behavior, as seen in line 11 of the `gresc` example.
+The format of a behavior's `.dtsi` file is identical to declaring an instance of the behavior in a user's keymap. The only major difference is that the value `/omit-if-no-ref/` should be placed adjacent to the label and name of the behavior, as seen in line 11 of the `gresc` example.
+
+:::caution
+
+If your behavior has its [`locality`](#api-structure) property set to anything other than `BEHAVIOR_LOCALITY_CENTRAL`, then the name of the node must be at most 8 characters long, or it will fail to be invoked on the peripheral half of a split keyboard.
+
+In the above example, `grave_escape` is too long, so it would need to be shortened, e.g.
+
+```dts
+// Behavior can be invoked on peripherals, so name must be <= 8 characters.
+/omit-if-no-ref/ gresc: gresc { ... };
+```
+
+:::
 
 After creating the `.dtsi` from above, update `app/dts/behaviors.dtsi` to include your newly predefined behavior instance, making it accessible by the devicetree.
 
diff --git a/docs/docs/development/new-shield.md b/docs/docs/development/new-shield.md
index 7f6a8644..dd63fa9b 100644
--- a/docs/docs/development/new-shield.md
+++ b/docs/docs/development/new-shield.md
@@ -11,37 +11,58 @@ import Metadata from "@site/src/data/hardware-metadata.json";
 
 ## Overview
 
-This guide will walk through the steps necessary to add ZMK support for a keyboard the uses a (Pro Micro compatible) addon MCU board to provide the microprocessor.
+This guide will walk through the steps necessary to add ZMK support for a keyboard that uses an add-on MCU board (e.g. Pro Micro compatible) to provide the microprocessor.
+
 The high level steps are:
 
+- From a template, create a new [Zephyr module](https://docs.zephyrproject.org/3.2.0/develop/modules.html) housed in a git repository containing one or more custom shields.
 - Create a new shield directory.
 - Add the base Kconfig files.
 - Add the shield overlay file to define the KSCAN driver for detecting key press/release.
 - (Optional) Add the matrix transform for mapping KSCAN row/column values to sane key positions. This is needed for non-rectangular keyboards, or where the underlying row/column pin arrangement does not map one to one with logical locations on the keyboard.
 - Add a default keymap, which users can override in their own configs as needed.
+- Add a `<my_shield>.zmk.yml` metadata file to document the high level details of your shield, and the features it supports.
+- Update the `build.yaml` file from the repository template to have some sample builds of the firmware to test.
 - Add support for features such as encoders, OLED displays, or RGB underglow.
 
-It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/2.5.0/guides/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing.
+It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/3.2.0/guides/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing.
 
 :::note
 ZMK support for split keyboards requires a few more files than single boards to ensure proper connectivity between the central and peripheral units. Check the following guides thoroughly to ensure that all the files are in place.
 :::
 
+## New Zephyr Module Repository
+
+The first step to creating the shield is to create a new Zephyr module repository from a template.
+
+:::note
+This guide assumes you already have a configured GitHub account. If you don't yet have one, go ahead and [sign up](https://github.com/join) before continuing.
+:::
+
+Follow these steps to create your new repository:
+
+- Visit https://github.com/zmkfirmware/unified-zmk-config-template
+- Click the green "Use this template" button
+- In the drop down that opens, click "Use this template".
+- In the following screen, provide the following information:
+  - A repository name, e.g. `my-shield-module`.
+  - A brief description, e.g. `ZMK Support For MyShield Keyboard`.
+  - Select Public or Private, depending on your preference.
+- Click the green "Create repository" button
+
 ## New Shield Directory
 
 :::note
-This guide describes how to add shield to the ZMK main repository. If you are building firmware for your
-own prototype or handwired keyboard, it is recommended to use your own user config repository. Follow the
-[user setup guide](user-setup.md) to create your user config repository first. When following the rest
-of this guide, replace the `app/` directory in the ZMK main repository with the `config/` directory in your
-user config repository. For example, `app/boards/shields/<keyboard_name>` should now be
-`config/boards/shields/<keyboard_name>`.
+This guide describes how to add a shield to an independently managed Zephyr module repository. This is the
+preferred way to handle boards and shields moving forward in ZMK, although the tooling to make this easier
+for users is still improving. ZMK does have a collection of boards/shields in the ZMK main repository, which are planned to be phased out, but until that is complete, there _may_ be a few select scenarios where adding your keyboard to ZMK itself is preferred. Due the volume of PRs and the focus of ZMK development not being merging of keyboard PRs, you are highly encouraged to use an out-of-tree Zephyr module repository to manage your definitions. Should you choose to try to get your keyboard included in ZMK main repository, the paths in the rest of the guide would be nested under the `app/` folder there instead. For example, `boards/shields/<keyboard_name>` should now be
+`app/boards/shields/<keyboard_name>`.
 :::
 
-Shields for Zephyr applications go into the `boards/shields/` directory; since ZMK's Zephyr application lives in the `app/` subdirectory of the repository, that means the new shield directory should be:
+Shields in Zephyr module "board root" go into the `boards/shields/` directory; that means the new shield directory in your module repository should be:
 
 ```bash
-mkdir app/boards/shields/<keyboard_name>
+mkdir boards/shields/<keyboard_name>
 ```
 
 ## Base Kconfig Files
@@ -92,10 +113,11 @@ config ZMK_KEYBOARD_NAME
 endif
 ```
 
-Similarly to defining the halves of a split board in `Kconfig.shield` it is important to set the `ZMK_KEYBOARD_NAME` for each half of a split keyboard.
-You'll also want to set which half is the central side. Most boards set it to the left.
-Then on the peripheral half, you'll want to turn USB on so that it shows USB status on displays properly.
-Finally, you'll want to turn on the split option for both sides. This can all be seen below.
+For split keyboards, `Kconfig.defconfig` needs to specify a few more options.
+Which side is central (usually the left) is determined via the configuration in this file.
+For that side, the keyboard name is assigned and the central config is set.
+The peripheral side is typically not assigned a name since only the central will be advertising for connections to other devices.
+Finally, the split config needs to be set for both sides:
 
 ```kconfig
 if SHIELD_MY_BOARD_LEFT
@@ -144,7 +166,6 @@ this might look something like:
 
     kscan0: kscan_0 {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
         diode-direction = "col2row";
 
         col-gpios
@@ -203,7 +224,6 @@ RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,2) RC(4,9) RC(3,6) RC(3,7)
 
     kscan0: kscan {
         compatible = "zmk,kscan-gpio-matrix";
-        label = "KSCAN";
 
         diode-direction = "col2row";
         row-gpios
@@ -348,9 +368,9 @@ See the [matrix transform section](../config/kscan.md#matrix-transform) in the K
 
 ## Default Keymap
 
-Each keyboard should provide an OOTB default keymap to be used when building the firmware, which can be overridden and customized by user configs. For "shield keyboards", this should be placed in the `app/boards/shields/<shield_name>/<shield_name>.keymap` file. The keymap is configured as an additional devicetree overlay that includes the following:
+Each keyboard should provide a default keymap to be used when building the firmware, which can be overridden and customized by user configs. For "shield keyboards", this should be placed in the `boards/shields/<shield_name>/<shield_name>.keymap` file. The keymap is configured as an additional devicetree overlay that includes the following:
 
-- A node with `compatible="zmk,keymap"` where each child node is a layer with a `bindings` array that binds each key position to a given behavior (e.g. key press, momentarily layer, etc).
+- A node with `compatible = "zmk,keymap"` where each child node is a layer with a `bindings` array that binds each key position to a given behavior (e.g. key press, momentary layer, etc).
 
 Here is an example simple keymap for the Kyria, with only one layer:
 
@@ -362,12 +382,7 @@ The two `#include` lines at the top of the keymap are required in order to bring
 
 ### Keymap Behaviors
 
-Further documentation on behaviors and bindings is forthcoming, but a summary of the current behaviors you can bind to key positions is as follows:
-
-- `kp` is the "key press" behavior, and takes a single binding argument of the key code from the 'keyboard/keypad" HID usage table.
-- `mo` is the "momentary layer" behavior, and takes a single binding argument of the numeric ID of the layer to momentarily enable when that key is held.
-- `trans` is the "transparent" behavior, useful to be place in higher layers above `mo` bindings to be sure the key release is handled by the lower layer. No binding arguments are required.
-- `mt` is the "mod-tap" behavior, and takes two binding arguments, the modifier to use if held, and the keycode to send if tapped.
+For the full documentation on the available behaviors for use in keymaps, start with reviewing [`kp`](../behaviors/key-press.md) and then use the sidebar to review the others available within ZMK.
 
 ## Metadata
 
@@ -395,6 +410,40 @@ siblings:
 
 You should place a properly named `foo.zmk.yml` file in the directory next to your other shield values, and fill it out completely and accurately. See [Hardware Metadata Files](/docs/development/hardware-metadata-files) for the full details.
 
+## Build File
+
+To help you test/verify your firmware, update the `build.yaml` to list your particular board/shield combinations you want built whenever changes are published to GitHub. Open `build.yaml` with your editor and add a combination, e.g.:
+
+```yaml
+# This file generates the GitHub Actions matrix
+# For simple board + shield combinations, add them
+# to the top level board and shield arrays, for more
+# control, add individual board + shield combinations to
+# the `include` property, e.g:
+#
+# board: [ "nice_nano_v2" ]
+# shield: [ "corne_left", "corne_right" ]
+# include:
+#   - board: bdn9_rev2
+#   - board: nice_nano_v2
+#     shield: reviung41
+#
+---
+include:
+  - board: nice_nano_v2
+    shield: <my_shield>
+```
+
+For split keyboards, you will need to specify the halves/siblings separately, e.g.:
+
+```yaml
+include:
+  - board: mikoto_520
+    shield: <my_shield>_left
+  - board: mikoto_520
+    shield: <my_shield>_right
+```
+
 ## Adding Features
 
 ### Encoders
@@ -432,7 +481,6 @@ In your device tree file you will need to add the following lines to define the
 ```dts
     left_encoder: encoder_left {
         compatible = "alps,ec11";
-        label = "LEFT_ENCODER";
         a-gpios = <PIN_A (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         b-gpios = <PIN_B (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
         steps = <80>;
@@ -489,17 +537,40 @@ Add additional bindings as necessary to match the default number of encoders on
 
 ## Testing
 
+### GitHub Actions
+
+Using GitHub Actions to build your new firmware can save you from doing any local [development setup](./setup.md),
+at the expense of a longer feedback loop if there are issues. To push your changes and trigger a build:
+
+- Add all your pending changes with `git add .`
+- Commit your changes with `git commit -m "Initial shield"`
+- Push the changes to GitHub with `git push`
+
+Once pushed, click on the "Actions" tab of the repo you created in the first step, and you should see a new build running. If the build is successful, there will be a new `firmware.zip` artifact shown on the summary screen you can download that will contain the new `.uf2` files that can be flashed to the device.
+
+### Local Build
+
+:::note
+To build locally, be sure you've followed the [development setup](./setup.md) guide first.
+:::
+
 Once you've fully created the new keyboard shield definition,
 you should be able to test with a build command like:
 
 ```sh
-west build --pristine -b nice_nano_v2 -- -DSHIELD=my_board
+west build --pristine -b nice_nano_v2 -- -DSHIELD=<my_shield> -DZMK_EXTRA_MODULES=/full/path/to/your/module
+# replace <my_shield> with e.g. <my_shield>_left for split keyboards, then repeat for <my_shield>_right
 ```
 
-The above build command generates `build/zephyr/zmk.uf2`. If your board
+The above build command generates a `build/zephyr/zmk.uf2` file that you can flash using the steps from the following section. See the dedicated [building and flashing page](build-flash.md) for more details.
+
+### Flashing
+
+If your board
 supports USB Flashing Format (UF2), copy that file onto the root of the USB mass
 storage device for your board. The controller should flash your built firmware
-and automatically restart once flashing is complete.
+and automatically restart once flashing is complete. If you need to flash an updated
+UF2 file with fixes, you can re-enter the bootloader by double tapping the reset button.
 
 Alternatively, if your board supports flashing and you're not developing from
 within a Dockerized environment, enable Device Firmware Upgrade (DFU) mode on
diff --git a/docs/docs/development/usb-logging.md b/docs/docs/development/usb-logging.md
index e50e7824..6a8f8564 100644
--- a/docs/docs/development/usb-logging.md
+++ b/docs/docs/development/usb-logging.md
@@ -83,3 +83,32 @@ You should see tio printing `Disconnected` or `Connected` when you disconnect or
 </Tabs>
 
 From there, you should see the various log messages from ZMK and Zephyr, depending on which systems you have set to what log levels.
+
+## Adding USB Logging to a Board
+
+Standard boards such as the nice!nano and Seeeduino XIAO family have the necessary configuration for logging already added, however if you are developing your own standalone board you may wish to add the ability to use USB logging in the future.
+
+To add USB logging to a board you need to define the USB CDC ACM device that the serial output gets piped to, as well as adding the console in the `chosen` node inside `<board>.dts`.
+
+Inside the USB device (`&usbd`), add the CDC ACM node:
+
+```dts
+&usbd {
+    status = "okay";
+    cdc_acm_uart: cdc_acm_uart {
+        compatible = "zephyr,cdc-acm-uart";
+    };
+};
+```
+
+Then you can add the `zephyr,console` binding in the `chosen` node:
+
+```dts
+/ {
+    chosen {
+        ...
+        zephyr,console = &cdc_acm_uart;
+    };
+    ...
+};
+```
diff --git a/docs/docs/features/backlight.md b/docs/docs/features/backlight.md
index c1b5db5d..eae4d2f9 100644
--- a/docs/docs/features/backlight.md
+++ b/docs/docs/features/backlight.md
@@ -37,12 +37,12 @@ There are various Kconfig options used to configure the backlight feature. These
 ## Adding Backlight to a board or a shield
 
 <Tabs
-defaultValue="shield"
+defaultValue="shieldpin"
 values={[
-{label: 'Adding to a board', value: 'board'},
-{label: 'Adding to a shield', value: 'shield'},
+{label: 'Adding to a board', value: 'boardpin'},{label: 'Adding to a shield', value: 'shieldpin'},
 ]}>
-<TabItem value="board">
+
+<TabItem value="boardpin">
 
 First, you must enable PWM by adding the following lines to your `Kconfig.defconfig` file:
 
@@ -58,43 +58,60 @@ config LED_PWM
 endif # ZMK_BACKLIGHT
 ```
 
-Then you have to add the following lines to your `.dts` file:
+Create a `<board>-pinctrl.dtsi` file if it does not already exist, and include it at the beginning of the `<board>.dts` file. `CONFIG_PINCTRL=y` must be added to to `<board>_defconfig` if it isn't already enabled.
+
+The pinctrl file has a `&pinctrl` node that encompasses all pinctrl settings, including I2C or SPI peripherals (e.g. WS2812 LEDs, Battery fuel gauges):
 
 ```dts
-&pwm0 {
-    status = "okay";
-    ch0-pin = <45>;
-    /* ch0-inverted; */
-};
-```
-
-The value `ch0-pin` represents the pin that controls the LEDs. With nRF52 boards, you can calculate the value to use in the following way: you need the hardware port and run it through a function.
-**32 \* X + Y** = `<Pin number>` where X is first part of the hardware port "PX.01" and Y is the second part of the hardware port "P1.Y".
-
-For example, _P1.13_ would give you _32 \* 1 + 13_ = `<45>` and _P0.15_ would give you _32 \* 0 + 15_ = `<15>`.
-
-If your board uses a P-channel MOSFET to control backlight instead of a N-channel MOSFET, you may want to enable `ch0-inverted`.
-
-Then you have to add the following lines inside the root devicetree node on the same file as before:
-
-```dts
-/ {
-    backlight: pwmleds {
-        compatible = "pwm-leds";
-        label = "Backlight LEDs";
-        pwm_led_0 {
-            pwms = <&pwm0 45>;
-            label = "Backlight LED 0";
+&pinctrl {
+    // Other pinctrl definitions for other hardware
+    pwm0_default: pwm0_default {
+        group1 {
+            psels = <NRF_PSEL(PWM_OUT0, 1, 13)>;
+        };
+    };
+    pwm0_sleep: pwm0_sleep {
+        group1 {
+            psels = <NRF_PSEL(PWM_OUT0, 1, 13)>;
+            low-power-enable;
         };
     };
 };
 ```
 
-The value inside `pwm_led_0` must be the same as you used before.
+Pin numbers are handled differently depending on the MCU. On nRF MCUs pins are configured using `(PWM_OUTX, Y, Z)`, where `X` is the PWM channel used (usually 0), `Y` is the first part of the hardware port (_PY.01_) and `Z` is the second part of the hardware port (_P1.Z_).
 
-:::info
-Note that every LED inside of the backlight node will be treated as a backlight LED, so if you have other PWM LEDs you need to declare them in a separate node. Refer to [Multiple backlight LEDs](#multiple-backlight-leds) if you have multiple backlight LEDs.
-:::
+For example, _P1.13_ would give you `(PWM_OUT0, 1, 13)` and _P0.15_ would give you `(PWM_OUT0, 0, 15)`.
+
+Add the PWM device to the `board.dts` file and assign the pinctrl definitions to it:
+
+```dts
+&pwm0 {
+    status = "okay";
+    pinctrl-0 = <&pwm0_default>;
+    pinctrl-1 = <&pwm0_sleep>;
+    pinctrl-names = "default", "sleep";
+};
+```
+
+Then add the following lines to the same `<board>.dts` file, but inside the root devicetree node:
+
+```dts
+/ {
+    backlight: pwmleds {
+        compatible = "pwm-leds";
+        pwm_led_0 {
+            pwms = <&pwm0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>;
+        };
+    };
+};
+```
+
+The value inside `pwm_led_0` after `&pwm0` must be the channel number. Since `PWM_OUT0` is defined in the pinctrl node, the channel in this example is 0.
+
+In this example, `PWM_MSEC(10)` is the period of the PWM waveform. This period can be altered if your drive circuitry requires different values or the frequency is audible.
+
+If your board uses a P-channel MOSFET to control backlight instead of a N-channel MOSFET, you may want to change `PWM_POLARITY_NORMAL` for `PWM_POLARITY_INVERTED`.
 
 Finally you need to add backlight to the `chosen` element of the root devicetree node:
 
@@ -107,7 +124,7 @@ Finally you need to add backlight to the `chosen` element of the root devicetree
 ```
 
 </TabItem>
-<TabItem value="shield">
+<TabItem value="shieldpin">
 
 You must first add a `boards/` directory within your shield folder. For each board that supports the shield you must create a `<board>.defconfig` file and a `<board>.overlay` file inside the `boards/` folder.
 
@@ -128,40 +145,55 @@ endif # ZMK_BACKLIGHT
 Then add the following lines to your `.overlay` file:
 
 ```dts
-&pwm0 {
-    status = "okay";
-    ch0-pin = <45>;
-    /* ch0-inverted; */
-};
-```
-
-The value `ch0-pin` represents the pin that controls the LEDs. With nRF52 boards, you can calculate the value to use in the following way: you need the hardware port and run it through a function.
-**32 \* X + Y** = `<Pin number>` where X is first part of the hardware port "PX.01" and Y is the second part of the hardware port "P1.Y".
-
-For example, _P1.13_ would give you _32 \* 1 + 13_ = `<45>` and _P0.15_ would give you _32 \* 0 + 15_ = `<15>`.
-
-If your shield uses a P-channel MOSFET to control backlight instead of a N-channel MOSFET, you may want to enable `ch0-inverted`.
-
-Then you have to add the following lines inside the root devicetree node on the same file:
-
-```dts
-/ {
-    backlight: pwmleds {
-        compatible = "pwm-leds";
-        label = "Backlight LEDs";
-        pwm_led_0 {
-            pwms = <&pwm0 45>;
-            label = "Backlight LED 0";
+&pinctrl {
+    // Other pinctrl definitions for other hardware
+    pwm0_default: pwm0_default {
+        group1 {
+            psels = <NRF_PSEL(PWM_OUT0, 1, 13)>;
+        };
+    };
+    pwm0_sleep: pwm0_sleep {
+        group1 {
+            psels = <NRF_PSEL(PWM_OUT0, 1, 13)>;
+            low-power-enable;
         };
     };
 };
 ```
 
-The value inside `pwm_led_0` must be the same as you used before.
+Pin numbers are handled differently depending on the MCU. On nRF MCUs pins are configured using `(PWM_OUTX, Y, Z)`, where `X` is the PWM channel used (usually 0), `Y` is the first part of the hardware port (_PY.01_) and `Z` is the second part of the hardware port (_P1.Z_).
 
-:::info
-Note that every LED inside of the backlight node will be treated as a backlight LED, so if you have other PWM LEDs you need to declare them in a separate node. Refer to [Multiple backlight LEDs](#multiple-backlight-leds) if you have multiple backlight LEDs.
-:::
+For example, _P1.13_ would give you `(PWM_OUT0, 1, 13)` and _P0.15_ would give you `(PWM_OUT0, 0, 15)`.
+
+Add the PWM device to the `<board>.overlay` file and assign the pinctrl definitions to it:
+
+```dts
+&pwm0 {
+    status = "okay";
+    pinctrl-0 = <&pwm0_default>;
+    pinctrl-1 = <&pwm0_sleep>;
+    pinctrl-names = "default", "sleep";
+};
+```
+
+Then add the following lines to the same `<board>.overlay` file, but inside the root devicetree node:
+
+```
+/ {
+    backlight: pwmleds {
+        compatible = "pwm-leds";
+        pwm_led_0 {
+            pwms = <&pwm0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>;
+        };
+    };
+};
+```
+
+In this example, `PWM_MSEC(10)` is the period of the PWM waveform. This period can be altered if your drive circuitry requires different values or the frequency is audible.
+
+If your board uses a P-channel MOSFET to control backlight instead of a N-channel MOSFET, you may want to change `PWM_POLARITY_NORMAL` for `PWM_POLARITY_INVERTED`.
+
+The value inside `pwm_led_0` after `&pwm0` must be the channel number. Since `PWM_OUT0` is defined in the pinctrl node, the channel in this example is 0.
 
 Finally you need to add backlight to the `chosen` element of the root devicetree node:
 
@@ -170,26 +202,9 @@ Finally you need to add backlight to the `chosen` element of the root devicetree
     chosen {
         zmk,backlight = &backlight;
     };
-}:
-```
-
-Optionally, on Pro Micro compatible shields you can add a LED GPIO node to your devicetree, this could be useful if you want your shield to be compatible with newer or untested boards. To do that you have to enable `CONFIG_LED_GPIO` in your `.conf` file and then add the following lines inside the root devicetree node of your `.dtsi` or `.dts` file:
-
-```dts
-/ {
-    backlight: gpioleds {
-        compatible = "gpio-leds";
-        label = "Backlight LEDs";
-        gpio_led_0 {
-            gpios = <&pro_micro 20 GPIO_ACTIVE_HIGH>;
-            label = "Backlight LED 0";
-        };
-    };
 };
 ```
 
-If no suitable `<board>.overlay` file is found, this node will act as a fallback, however, without PWM, backlight has limited functionality.
-
 </TabItem>
 </Tabs>
 
@@ -197,35 +212,44 @@ If no suitable `<board>.overlay` file is found, this node will act as a fallback
 
 It is possible to control multiple backlight LEDs at the same time. This is useful if, for example, you have a Caps Lock LED connected to a different pin and you want it to be part of the backlight.
 
-In order to do that, first you need to enable PWM for each pin:
+In order to do that, first configure PWM for each pin in the pinctrl node:
 
 ```dts
-&pwm0 {
-    status = "okay";
-    ch0-pin = <45>; /* LED 0 */
-    ch1-pin = <46>; /* LED 1 */
-    ch2-pin = <47>; /* LED 2 */
-    ...
+&pinctrl {
+    // Other Pinctrl definitions go here
+    pwm0_default: pwm0_default {
+        group1 {
+            psels = <NRF_PSEL(PWM_OUT0, 0, 20)>, // LED 0
+                    <NRF_PSEL(PWM_OUT1, 0, 22)>, // LED 1
+                    <NRF_PSEL(PWM_OUT2, 0, 24)>; // LED 2
+        };
+    };
+    pwm0_sleep: pwm0_sleep {
+        group1 {
+            psels = <NRF_PSEL(PWM_OUT0, 0, 20)>, // LED 0
+                    <NRF_PSEL(PWM_OUT1, 0, 22)>, // LED 1
+                    <NRF_PSEL(PWM_OUT2, 0, 24)>; // LED 2
+            low-power-enable;
+        };
+    };
 };
 ```
 
-This part may vary based on your MCU as different MCUs may have a different number of modules and channels.
+This part will vary based on your MCU as different MCUs have a different number of modules, channels and configuration options.
 
-Then you can simply add each of your LED to the backlight node:
+Add each of your LEDs to the backlight node in the same manner as for one LED, using the channel number definitions in the pinctrl node:
 
 ```dts
 backlight: pwmleds {
     compatible = "pwm-leds";
-    label = "Backlight LEDs";
-    pwm_led_0 {
-        pwms = <&pwm0 45>; /* LED 0 */
+    pwm_led_0: pwm_led_0 {
+        pwms = <&pwm0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>;
     };
-    pwm_led_1 {
-        pwms = <&pwm0 46>; /* LED 1 */
+    pwm_led_1: pwm_led_1 {
+        pwms = <&pwm0 1 PWM_MSEC(10) PWM_POLARITY_NORMAL>;
     };
-    pwm_led_2 {
-        pwms = <&pwm0 47>; /* LED 2 */
+    pwm_led_2: pwm_led_2 {
+        pwms = <&pwm0 2 PWM_MSEC(10) PWM_POLARITY_NORMAL>;
     };
-    ...
 };
 ```
diff --git a/docs/docs/features/battery.md b/docs/docs/features/battery.md
index 8bf78207..4bfeb129 100644
--- a/docs/docs/features/battery.md
+++ b/docs/docs/features/battery.md
@@ -34,7 +34,6 @@ Once you have the sensor driver defined, add a `zmk,battery` property to the `ch
 
     vbatt: vbatt {
         compatible = "zmk,battery-nrf-vddh";
-        label = "VBATT";
     };
 }
 ```
diff --git a/docs/docs/features/underglow.md b/docs/docs/features/underglow.md
index b5c4c703..13f0d8c7 100644
--- a/docs/docs/features/underglow.md
+++ b/docs/docs/features/underglow.md
@@ -98,7 +98,6 @@ Here's an example on a definition that uses P0.06:
 
   led_strip: ws2812@0 {
     compatible = "worldsemi,ws2812-spi";
-    label = "WS2812";
 
     /* SPI */
     reg = <0>; /* ignored, but necessary for SPI bindings */
@@ -142,7 +141,6 @@ Here's another example for a non-nRF52 board on `spi3`:
 
   led_strip: ws2812@0 {
     compatible = "worldsemi,ws2812-spi";
-    label = "WS2812";
 
     /* SPI */
     reg = <0>;
diff --git a/docs/docs/hardware.mdx b/docs/docs/hardware.mdx
index 6f377073..7bc98f96 100644
--- a/docs/docs/hardware.mdx
+++ b/docs/docs/hardware.mdx
@@ -41,7 +41,7 @@ export const toc = [
 ];
 
 With the solid technical foundation of Zephyrâ„¢ RTOS, ZMK can support a wide diversity of hardware targets.
-That being said, there are currently only a few specific [boards](/docs/faq#what-is-a-board)/[shields](faq.md#what-is-a-shield) that have been implemented and tested by the ZMK contributors.
+That being said, there are specific [boards](faq.md#what-is-a-board)/[shields](faq.md#what-is-a-shield) that have been implemented and tested by the ZMK contributors, listed below.
 
 <HardwareList items={Metadata} />
 
@@ -49,17 +49,11 @@ That being said, there are currently only a few specific [boards](/docs/faq#what
   Other Hardware
 </Heading>
 
-In addition to the basic keyboard functionality, there is some initial support for additional keyboard hardware:
-
-- Encoders
-- Displays
-- RGB Underglow
-- Backlight
-
-Until detailed documentation is available, feel free to ask questions about how these are supported in the [Discord server](https://zmk.dev/community/discord/invite).
+In addition to the basic keyboard functionality, there is also support for additional keyboard hardware such as encoders, RGB underglow, backlight and displays.
+Please see pages under the "Features" header in the sidebar for details.
 
 <Heading as="h2" id="contributing">
   Contributing
 </Heading>
 
-If you'd like to add support for a new keyboard shield, head over to the [New Keyboard Shield](development/new-shield.md) documentation.
+If you'd like to add support for a new keyboard shield, head over to the [New Keyboard Shield](development/new-shield.md) documentation and note the [clean room design requirements](development/clean-room.md).