cc-firmware: per-variant FQBN — XIAO needs the Seeed board variant #4
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Build Claude Code Duck firmware variants (Ducky PCB + XIAO Seeed S3) | |
| # and attach them as merged single-file binaries to a GitHub Release. | |
| # The web flasher (docs/flash/index.html) references the binaries via | |
| # the "latest release" URL pattern, so each successful release auto- | |
| # updates what gets installed when a user clicks Flash on the Claude | |
| # Code Duck tab. | |
| # | |
| # Trigger: push of a tag matching `cc-v*` (e.g., cc-v1.0.0). Hand- | |
| # trigger: workflow_dispatch from the Actions tab. | |
| # | |
| # Note: separate from the bambu firmware workflow so each product | |
| # moves on its own cadence — `cc-v*` tags fire this one, `bambu-v*` | |
| # tags fire the bambu one. Same .bin upload pattern, different | |
| # release assets (cc-ducky.bin / cc-xiao.bin). | |
| name: Claude Code Duck firmware release | |
| on: | |
| push: | |
| tags: | |
| - 'cc-v*' | |
| workflow_dispatch: | |
| permissions: | |
| contents: write # needed to create releases / upload assets | |
| jobs: | |
| build-and-release: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - variant: ducky | |
| sketch_dir: firmware/rubber_duck_s3_ducky | |
| sketch_file: rubber_duck_s3_ducky.ino | |
| asset_name: cc-ducky.bin | |
| label: Claude Code Duck — Ducky PCB | |
| # Generic ESP32-S3 board — Config.h uses raw GPIO numbers. | |
| fqbn: 'esp32:esp32:esp32s3:USBMode=hwcdc,CDCOnBoot=cdc,PartitionScheme=default_8MB,FlashSize=8M,PSRAM=opi' | |
| - variant: xiao | |
| sketch_dir: firmware/rubber_duck_s3 | |
| sketch_file: rubber_duck_s3.ino | |
| asset_name: cc-xiao.bin | |
| label: Claude Code Duck — XIAO Seeed S3 | |
| # Seeed-specific board variant — its pins_arduino.h | |
| # defines the D0-D10 pin aliases that the sketch's | |
| # Config.h references (BUTTON_PIN=D5, I2S_BCLK=D1, etc.). | |
| # Generic esp32s3 doesn't define those, hence the prior | |
| # "'D5' not declared in this scope" build break. | |
| fqbn: 'esp32:esp32:XIAO_ESP32S3:USBMode=hwcdc,CDCOnBoot=cdc,PartitionScheme=default_8MB,FlashSize=8M,PSRAM=opi' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install arduino-cli | |
| # Official action — handles install, PATH, and PATH-on-windows. | |
| # Replaces a manual curl|sh pipeline that needed $BINDIR | |
| # pre-created and broke on the first run. | |
| uses: arduino/setup-arduino-cli@v2 | |
| - name: Install ESP32 board package | |
| run: | | |
| arduino-cli config init | |
| arduino-cli config add board_manager.additional_urls \ | |
| https://espressif.github.io/arduino-esp32/package_esp32_index.json | |
| arduino-cli core update-index | |
| # Pin to a known-good ESP32 core. Bump deliberately when | |
| # validating against a newer arduino-esp32 release. | |
| arduino-cli core install esp32:esp32@3.0.7 | |
| - name: Install esptool (for merge_bin) | |
| run: pip install esptool | |
| - name: Compile ${{ matrix.label }} | |
| # FQBN: esp32:esp32:esp32s3 with USB CDC on boot so the chip | |
| # appears as /dev/cu.usbmodem* without an external UART bridge. | |
| # PSRAM=opi for the WROOM-1 (ducky PCB) — XIAO Sense's S3 also | |
| # has PSRAM enabled in its default partition. PartitionScheme | |
| # default_8MB to match the 8MB flash on both boards. | |
| # | |
| # USB manufacturer/product descriptor flags come from each | |
| # sketch's build_opt.h — arduino-cli picks that up natively | |
| # since v0.21. We don't pass --build-property here because | |
| # the spaces in "Duck Duck Duck" don't survive bash quoting | |
| # cleanly through to the gcc command line. | |
| run: | | |
| arduino-cli compile \ | |
| --fqbn '${{ matrix.fqbn }}' \ | |
| --output-dir build_${{ matrix.variant }} \ | |
| ${{ matrix.sketch_dir }} | |
| - name: Merge into single flashable image | |
| # arduino-cli output: <sketch>.ino.bootloader.bin / | |
| # .partitions.bin / .ino.bin. Merge into one offset-0 binary | |
| # so the ESP Web Tools manifest can reference a single file. | |
| run: | | |
| cd build_${{ matrix.variant }} | |
| ls -la | |
| BOOT=$(ls *.bootloader.bin | head -n1) | |
| PART=$(ls *.partitions.bin | head -n1) | |
| APP=$(ls *.ino.bin | head -n1) | |
| esptool.py --chip esp32s3 merge_bin \ | |
| -o ../${{ matrix.asset_name }} \ | |
| --flash_mode dio --flash_size 8MB --flash_freq 80m \ | |
| 0x0 "$BOOT" \ | |
| 0x8000 "$PART" \ | |
| 0x10000 "$APP" | |
| cd .. | |
| ls -la ${{ matrix.asset_name }} | |
| - name: Upload merged binary as artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.asset_name }} | |
| path: ${{ matrix.asset_name }} | |
| if-no-files-found: error | |
| release: | |
| needs: build-and-release | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/cc-v') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download all variant binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist | |
| - name: Flatten artifact dir layout | |
| run: | | |
| mkdir -p release | |
| find dist -name '*.bin' -exec cp {} release/ \; | |
| ls -la release/ | |
| - name: Create / update GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: Claude Code Duck firmware ${{ github.ref_name }} | |
| files: release/*.bin | |
| generate_release_notes: true | |
| body: | | |
| Pre-built firmware binaries for the Claude Code Duck (Mac | |
| companion that watches your Claude Code session and | |
| reacts via voice + servo + LED). | |
| **Flash from a browser:** https://ideo.github.io/Rubber-Duck/flash/ | |
| (Chrome / Edge — uses WebSerial, no install needed.) | |
| **Flash from the command line:** | |
| ``` | |
| python -m esptool --chip esp32s3 -p /dev/cu.usbmodem101 \ | |
| write_flash 0x0 cc-ducky.bin | |
| ``` | |
| Variants: | |
| - `cc-ducky.bin` — official IDEO Duck PCB (custom WROOM-1) | |
| - `cc-xiao.bin` — DIY build on standard XIAO Seeed ESP32-S3 |