zmk-feature-codex-micro is a keyboard-independent ZMK module. It exposes six Codex Micro-style Agent Keys and the common commands as a standard ZMK behavior. Your keyboard repository keeps ownership of its matrix, layers, and physical keys; the module handles protocol framing, USB, Bluetooth, routing, and Agent state.

Which keyboards can use it?

The module does not depend on Ferris Sweep, Sweep Pro, e-ink, or a particular matrix. A ZMK central half with USB device support and sufficient flash and RAM can bind &codex_key. On a split keyboard, enable the feature only on the central; the peripheral uses normal firmware.

  • With a display: subscribe to the public state event and render six-Agent status.
  • Without a display: all Agent and command keys work; read status in ChatGPT.
  • USB: a second vendor-defined HID interface leaves normal keyboard HID intact.
  • Bluetooth: an encrypted HID-over-GATT channel follows the active ZMK profile.
Your keymapChooses layers and physical keys
ZMK moduleActions, protocol, and routing
ChatGPTInterprets actions and returns state

Before you begin

  • Start from a ZMK config repository that already builds successfully.
  • Identify the central half, usually the half that connects over USB.
  • Pin tested ZMK and module commits or release tags.
  • Keep a known-good firmware build without Codex for diagnosis and rollback.

Step 1: Add the module to the west manifest

Add the NXTKB remote and module project to config/west.yml:

manifest:
  remotes:
    - name: zmkfirmware
      url-base: https://github.com/zmkfirmware
    - name: nxtkb
      url-base: https://github.com/nxtkb
  projects:
    - name: zmk
      remote: zmkfirmware
      revision: <tested-zmk-commit>
      import: app/west.yml
    - name: zmk-feature-codex-micro
      remote: nxtkb
      revision: <release-tag-or-commit>
  self:
    path: config

Avoid depending on main for distributed firmware. Pinned revisions let you reproduce an older build after ZMK or the module evolves.

Step 2: Apply the temporary official-ZMK patch

Codex USB requires interrupt-OUT. Zephyr's current option gives both the normal keyboard HID_0 and Codex HID_1 an OUT endpoint, while official ZMK does not yet register an HID_0 receive callback. Until an equivalent fix is merged upstream, apply the focused patch included with the module:

west update
west patch -sm zmk-feature-codex-micro apply

west update and west build do not apply module patches automatically, so the explicit west patch step is required. The module also provides a reusable GitHub Actions workflow that performs this step before compiling. If the module is outside your west workspace, use git apply with zephyr/patches/zmk/zmk-usb-hid-interrupt-out.patch instead. This is not an NXTKB ZMK fork: the patch only lets the official ZMK keyboard interface safely consume or discard its own OUT report. Codex traffic remains isolated on HID_1. Stop applying the patch after the pinned official ZMK revision includes an equivalent callback.

Step 3: Choose USB or Bluetooth transport

Add the snippet to the central build in build.yaml. USB only:

include:
  - board: nice_nano//zmk
    shield: corne_left
    snippet: nxtkb-codex-micro-usb

USB and Bluetooth:

include:
  - board: nice_nano//zmk
    shield: corne_left
    snippet: nxtkb-codex-micro-usb nxtkb-codex-micro-ble

Do not add a snippet to the right peripheral:

  - board: nice_nano//zmk
    shield: corne_right

Step 4: Bind actions in the keymap

Include the module behavior and key IDs near the top of the keymap:

#include <behaviors.dtsi>
#include <behaviors/codex_key.dtsi>
#include <dt-bindings/nxtkb/codex.h>

Place the actions on any layer. This fragment shows the core bindings; a real layer must still contain the complete binding count required by your keyboard:

codex_layer {
    bindings = <
        &codex_key CODEX_AGENT_0
        &codex_key CODEX_AGENT_1
        &codex_key CODEX_AGENT_2
        &codex_key CODEX_AGENT_3
        &codex_key CODEX_AGENT_4
        &codex_key CODEX_AGENT_5
        &codex_key CODEX_FAST
        &codex_key CODEX_APPROVE
        &codex_key CODEX_DECLINE
        &codex_key CODEX_SPLIT
        &codex_key CODEX_MIC
        &codex_key CODEX_SEND
    >;
};
ConstantChatGPT action
CODEX_AGENT_0CODEX_AGENT_5Select the six Agent slots
CODEX_FASTFast mode
CODEX_APPROVEApprove an action
CODEX_DECLINEDecline an action
CODEX_SPLITSplit the current chat into a new chat
CODEX_MICUse the computer microphone for voice input
CODEX_SENDSend the current input

Use the repository's complete Corne example as a reference. CI also builds it as the non-NXTKB integration test.

Optional: render Agent state

A display is not a protocol dependency. A screen or LED module can subscribe to nxtkb_codex_state_changed, then call nxtkb_codex_state_get(). The snapshot contains six slots, the active slot, normalized states, selection flags, and original RGB values.

#include <nxtkb/codex/events.h>
#include <nxtkb/codex/state.h>

Your UI remains in the keyboard or display module, keeping the Codex core independent of any screen.

Pair Bluetooth again after the first upgrade

Hosts cache a keyboard's HID report map. After first enabling the BLE snippet, forget the old keyboard on the computer, clear the matching ZMK profile, and pair again. Toggling Bluetooth alone normally does not replace the cached capability description.

Codex actions follow the currently selected ZMK USB output or Bluetooth profile. Other computers remain connected and retain independent Agent state; switching Codex does not require disconnecting every host.

Device identity and ChatGPT discovery

The ChatGPT desktop app currently has no documented third-party Codex Micro registration flow. Integrators must use identifiers they are authorized to use and validate how the installed app discovers devices. Until an official discovery or certification path exists, treat this project as development, research, and interoperability work—not an officially certified integration.

Pre-release checklist

  • Both USB-only and USB+BLE central builds pass.
  • The peripheral still builds without a Codex snippet.
  • Normal keyboard, consumer, mouse, trackpad, and ZMK Studio behavior has no regression.
  • Check flash and RAM on the target controller, not only UF2 file size.
  • Re-pair every Bluetooth profile that has gained Codex BLE.
  • Test USB, Bluetooth, output switching, and separate computers.
  • Never publish a UF2 built with an experimental identity.

Where to start

The module, patch, integration documentation, and Corne example live in nxtkb/zmk-feature-codex-micro. First reproduce the example in your ZMK environment, then carry the same west project, snippets, and behavior bindings into your actual keyboard.