# Unboxing the ESP-Mosaico: ChatCoding and VibeCoding on an Agent-First Dev Board

> *Disclosure: Espressif sent me the ESP-Mosaico kit used in this post. The opinions and results are my own.*

## Introduction

Most dev boards ship with a pinout diagram and a blinky example. The ESP-Mosaico is a new type of modular dev board that ships with two ways for an AI agent to program it. Espressif describes it as "a modular development board built for coding agents", and the board is designed around that idea rather than having it bolted on later.

There are two modes. In **ChatCoding**, you message the device in plain language, and an agent running against the board turns the request into a working behavior on the spot. In **VibeCoding**, a coding agent on your computer writes, builds, flashes, and tests real ESP-IDF firmware on the board.

In this post, I cover what comes in the box, experiment with both modes, and run the same small task through each to compare them. I close with how this maps to Rust, since that is ultimately where I want to take it.

> **TL;DR**
> 
> *   The hardware is polished: a sharp 2.16" AMOLED, a solid build, and modules that identify themselves through an ID EEPROM.
>     
> *   ChatCoding is the easiest way in, with no toolchain needed. In my test, it struggled to identify the attached hardware and did not produce a working light meter.
>     
> *   VibeCoding with Claude Code built a Snake game and then a working light meter on the first try, helped a lot by Espressif's template and BSP drivers.
>     
> *   There is no Rust support for the board yet, but the VibeCoding template is a good blueprint for what a Rust version would need.
>     

> 🚀 **ESP-Mosaico is live on Product Hunt.** If you like what you see here, please support the launch with an upvote: **https://www.producthunt.com/products/esp-mosaico?launch=esp-mosaico** #ESPMosaico #Espressif #ProductHunt

Let's get started.

## 📦 Unboxing & Contents

![The ESP-Mosaico box with the CoreBoard, camera module, and Interaction module](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/2e04b08a-8f0d-4b5a-b12a-3325abeebcd5.jpg align="center")

My kit came with three pieces:

*   **ESP-Mosaico CoreBoard**: the main board, with the display, battery, and most of the sensors.
    
*   **Camera module**: plugs into the left expansion slot only.
    
*   **Multi-function Interaction module**: a sensor and I/O board that fits either slot.
    

![The camera module installed in the CoreBoard's left slot](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/749ad37b-f6b0-4441-8878-53110351e5dc.jpg align="center")

*The camera module installed in the left slot. Image: Espressif*

The CoreBoard is built around the **ESP32-S31**, a newer Espressif chip. Here is what is on it:

| Feature | Details |
| --- | --- |
| SoC | ESP32-S31, dual-core RISC-V, 512 KB SRAM. Espressif lists up to 320 MHz; `esptool chip-id` reported 300 MHz on my board |
| Flash | 16 MB SPI-NAND |
| Display | 2.16" 480×480 AMOLED with touch (CO5300 over QSPI) |
| Audio | ES8311 codec with NS4150B amplifier, microphone and speaker |
| Motion | BMI270 6-axis IMU, two BMM150 magnetometers |
| Power | 65 mAh battery, TP4057 charger, BQ27220 fuel gauge |
| Feedback | Vibration motor |
| Wireless | Wi-Fi 6, Bluetooth 5.4, 802.15.4 (Thread / Zigbee) |
| Expansion | Two 2×10 2.54 mm headers (left and right slots) |

![ESP-Mosaico CoreBoard overview: AI key, speaker, left and right extension connectors, BOOT, USB-C, and ON/OFF](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/809d88b0-db4f-454b-bccb-e4411b161a20.jpg align="center")

*Image: Espressif*

I used the Interaction module for the tests in this post. It carries:

*   **GL5506 photoresistor** for ambient light, read through the ADC.
    
*   **AS312 PIR sensor** for motion detection.
    
*   **IR LED** driven through an AO3400A MOSFET, for NEC remote-control codes at 38 kHz.
    
*   **Six WS2812 RGB LEDs**.
    
*   **Two capacitive touch keys**.
    
*   **An AT24C02 EEPROM** holds a board ID so the CoreBoard can tell which module is plugged in and in which slot.
    

That ID EEPROM is a small detail, but it matters for the agent story. An agent can only write correct code for a module if it knows the module is there, and the board can tell it.

![The Interaction module connected to the CoreBoard's right slot (top) and left slot (bottom)](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/b9f1e87d-511a-4b20-b943-c0a9edcf24d4.jpg align="center")

*The Interaction module in the right slot (top) and the left slot (bottom). Image: Espressif*

My first impression is that the kit is polished. The build quality is good across all three pieces, and the AMOLED display is sharp and clear. The one thing that left me guessing was the camera module. It has a hinge that lets it fold, and there are two LEDs on the back, but nothing in the box or the guide made it clear what those LEDs are for.

One thing I found annoying was the function button at the top, labeled "AI KEY" in Espressif's diagram. When holding the Mosaico naturally in one hand and pressing the on/off button, I frequently pressed it by mistake.

The modularity also seems to go beyond the sensor modules. Espressif's launch material says you can "combine multiple Mosaico devices and arrange them your way", and the hardware guide lists magnetic expansion as one of the target applications. There are contacts and magnets around the sides of the device that seem to be meant for this, though it is still not clear to me how it works.

![Multiple ESP-Mosaico devices arranged in a grid](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/8d113d4b-393b-4f2f-b1ab-d392d467d4a5.jpg align="center")

*Image: Espressif*

## 💬 ChatCoding

### What It Is

ChatCoding is the mode the board ships in. The agent here is Espressif's **ESP-Claw**. You talk to it through a chat channel, and it turns the request into a skill that runs on the board. The language model and speech recognition run in the cloud, not on the ESP32-S31. The board ships with a factory-provided allowance for basic use, and you can add your own API keys for heavier use. I started with the default allowance and later switched to my own key.

ESP-Claw comes with a set of built-in skills: Quick Ask, AI Create, Install Skill, Remember, Plan, and Schedule. Under the hood, the automation layer is Lua scripting.

You do not need a phone or a messaging app to use it. The board's home screen offers Quick Ask, AI Create, and Install Skill directly, with New Session and Continue buttons and a hold-to-talk input at the bottom.

![The ESP-Mosaico home screen next to the Interaction module](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/c7b2ab2f-3f7f-49cb-a122-b8098456bbaa.jpg align="center")

I did not try this route. Typing on a 2.16" screen is cramped, and talking to it is probably the more natural option. For this post, I set up Telegram, but I plan to come back to the on-device voice route in the future.

There is also a button at the top, labeled "AI KEY" in Espressif's diagram, that works more like a function button. My initial intuition was that pressing it would pop up a menu to issue a voice command to the agent, but pressing it did not seem to do anything. According to the hardware user guide, a short press goes back and a long press opens AI Create.

### Setup

The first step is getting the board on Wi-Fi. The guide offers a phone-based flow where you scan a code shown on the display and finish setup on your phone. The phone connects to the Mosaico as an access point, it seems, and gets routed to a capture page to enter the connection information. That didn't work for me; for some reason, it kept failing, even after restarts. What did work was entering the Wi-Fi details directly on the Mosaico's touchscreen.

Once connected, the board shows a local network address. Opening that address in a browser brings up a control panel served by the device itself. I created a Telegram bot, pasted its bot token into the instant messaging settings, and restarted the board. After the restart, I could message it from Telegram. I sent a simple hello, and it replied.

### The Control Panel

The control panel is where most of ESP-Claw's configuration lives, and it is worth a walk-through because it shows how the agent is put together. It is organized in tabs.

![The ESP-Claw control panel sidebar](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/e9703380-e910-40e5-9a83-1c8b40b88106.jpg align="center")

**System status** shows the network state and storage, and has buttons to restart the device and reload its status.

**System settings** is the largest tab, split into sections:

*   **Basic settings**: Wi-Fi, plus advanced options such as the time zone.
    
*   **LLM settings**: the model behind the agent. There is a list of providers to choose from, including OpenAI, DeepSeek, Anthropic, Kimi, and MiniMax, each taking an API key and a model name. There is also a `Trial (OpenAI + Qwen)` preset, which appears to be the factory allowance.
    

![The LLM settings in the ESP-Claw control panel, with DeepSeek V4 Pro configured](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/6bd03535-14ff-4098-8672-fb6d7c4f646c.png align="center")

*   **Speech recognition settings**: the speech-to-text service used when you talk to the device, with a couple of presets including Qwen.
    
*   **Instant messaging settings**: the chat channels. The options are WeChat, QQ, Feishu, and Telegram. This is where the Telegram bot token goes.
    
*   **Web search settings**: API keys for search providers such as Brave Search and Tavily, so the agent can look things up.
    

**Memory** holds the files the agent loads as context: long-term memory, soul, identity, and user info. If you have used an agent framework like OpenClaw, this structure will look familiar.

**Web chat** lets you talk to the board directly from the browser, without going through a messaging service.

**Capabilities** lists the compiled capability groups and lets you choose which ones are available at runtime. Each group can also be marked as "LLM visible", which keeps it listed in the planner's context at all times. The groups include the agent manager and the messaging channels, among others. On my board, all 19 groups were enabled and 6 were LLM visible.

![The Capabilities tab](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/223bafa3-5336-4b6e-a364-8e0d15d8ea5f.png align="center")

**Lua modules** selects which compiled Lua modules are registered when the Lua runtime starts. The list maps closely to the hardware: ADC, GPIO, I2C, MCPWM, PCNT, RMT, Touch, and more. All 28 were enabled by default. Changes here take effect after a restart.

![The Lua modules tab](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/8f01bffb-fa06-4477-824d-0b15b9e82e82.png align="center")

**Files** is the last tab. I could not work out what it is for from the panel itself, and the guide does not explain it.

Two things stood out to me here. First, the agent's building blocks for hardware access are all there as Lua modules, so the agent is not missing the means to read an ADC or drive a GPIO. Second, the Memory tab is the board's equivalent of a `CLAUDE.md` file. Keep both in mind for the next section.

### The Light Meter Test

For a real test, I asked the agent for something a bit generic that also uses the Interaction module:

> *"Show the light level as a bar on the screen and on the LEDs."*

I sent it at 1:28 PM. ESP-Claw replied within the minute with a plan: a helper agent would check the light sensor, display, and LED strip, then wire up a live bar in both places. When I asked for an update at 2:12 PM, it checked the helper's status and its running Lua jobs, and reported that the helper was still identifying the hardware. By 2:41 PM, 73 minutes in, nothing had been drawn or lit.

![ESP-Claw handling the light meter request over Telegram](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/2411e0b1-3015-4301-90cc-9aee84697e78.jpg align="center")

I also noticed quick battery drain. I unplugged the board at 2:12 PM, and by 2:41 PM the battery was nearly empty. The battery is only 65 mAh, and the board was running the AMOLED, Wi-Fi, and an agent session the whole time, so treat it as a desk board with a battery, not a portable one.

This first run used the factory-provided keys, which Espressif describes as intended for "basic questions and simple programming." So I added a DeepSeek API key and selected DeepSeek V4 Pro. Connecting took a few tries, and the control panel only reported `ESP_ERR_HTTP_CONNECT` and then a generic `ERROR`. What worked was a base URL of exactly `https://api.deepseek.com` (no `/v1`), a model name of `deepseek-v4-pro`, and a restart. If you add your own provider, verify the key with `curl` first.

I sent the same request again at 3:02 PM. Two minutes later, the agent came back with a confident and wrong verdict:

![ESP-Claw with DeepSeek V4 Pro reporting its hardware findings](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/2e0d9a4d-ce2b-42ff-a486-7ac4295437a4.jpg align="center")

*   The board is an "ESP32-S3". It is an ESP32-S31.
    
*   There is no light sensor, because "an I2C scan confirmed no light sensor is attached". The GL5506 is a photoresistor on an ADC input, which an I2C scan cannot see.
    
*   There are no addressable LEDs. The WS2812s use a single data line, which an I2C scan also cannot see.
    
*   The board "does have a camera". No camera module was plugged in.
    

At 3:07 PM, I replied with the missing facts: the Interaction module is plugged in, the GL5506 is on an ADC input, there are six WS2812 LEDs, the ID EEPROM is at I2C address 0x50, and there is no camera. Over the next six minutes, it went through 18 rounds, posting a progress note for each. It found a built-in `light_switch` skill, failed to read the ID EEPROM (`ESP_ERR_INVALID_RESPONSE`), scanned I2C port 0 without finding anything at 0x50, and concluded that its `board_hardware_info` skill is a static file that does not cover pluggable modules.

![ESP-Claw's round-by-round progress notes after the correction](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/c54808e1-7314-4b3e-b235-add14c3c2f0e.png align="center")

At 3:13 PM, it accepted my correction and warned that the session history was too large for the device's storage, so I should start a new session. By 3:23 PM, there was no further reply, so I stopped. Across two models and nearly two hours, ChatCoding did not produce a working light meter.

![The session storage warning and the agent's reply to the correction](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/b9004072-ae52-49dc-ad26-717a0f5e104b.png align="center")

The agent was not short on tools. The ADC and GPIO Lua modules were enabled from the start. It was missing the board description. The board detected the Interaction module through its ID EEPROM, but that knowledge didn't reach the agent, and the agent's own probing couldn't find the EEPROM that the driver later reads without trouble. I did not test it, but the Memory tab looks like the natural place to fix this. Writing the module's pinout into the agent's memory once could save every helper from rediscovering it, the same way a `CLAUDE.md` file does for a coding agent. Ideally, the firmware would do this automatically when it detects a module.

## 🧑‍💻 VibeCoding

### What It Is

VibeCoding moves the agent to your computer. Espressif provides a project template, `esp-mosaico-vibe`, that sets up a coding agent with what it needs to work on the board:

*   An **ESP-IDF** toolchain targeting `esp32s31`. At the time of writing this is a preview target on ESP-IDF `master`, not yet in a stable release.
    
*   **MCP servers** for ESP Pilot and the ESP Component Registry, wired through `.mcp.json`.
    
*   **Agent skills** under `.agents/skills/`, plus `CLAUDE.md` and `AGENTS.md` guidance files.
    
*   A `mosaico.py` CLI for flashing, updating, and recovering the board.
    

The template works with Claude Code, Cursor, and Codex. The agent runs the full loop on its own: write code, build, flash, test on the board, fix, repeat.

One thing to know before trying it: VibeCoding flashes your own firmware onto the board, replacing the factory firmware that ChatCoding runs on. `mosaico.py recover` brings the board back to a working state if needed.

### Setup

I connected the board over USB, put it in download mode, and opened Claude Code (desktop app, Claude Opus 5.5 at medium effort) in the cloned `esp-mosaico-vibe` repository. From there, Claude Code set up the environment on its own. It read the guidance files and skills, cloned ESP-IDF at the exact commit `AGENTS.md` pins, and installed only the ESP32-S31 toolchain. The ESP-IDF install took about 7 minutes. Along the way, it also repaired a broken `esptool` install on my machine and added a missing Python dependency.

One note on the template: the MCP servers listed in `.mcp.json` were not connected in my session. Claude Code got everything it needed by reading the repository headers and source files.

Getting the laptop to see the board was the weak spot. The board kept dropping off USB while it sat idle in download mode, roughly a minute or two after the last command. Re-enumeration sometimes took 19 seconds, and once about two and a half minutes. Several times I had to put it back into download mode by pressing BOOT and the on/off button together, sometimes more than once, before it showed up. Claude Code also kept suspecting a USB hub, even though I plugged the board directly into my Mac. In the end, I wrote a small shell loop that waited for the board to reappear and started the flash about 2 seconds later. That got it through.

The template never writes to flash with `esptool` directly. `AGENTS.md` forbids it. Instead, `mosaico.py recover` writes a base firmware called Vibe Mode through the ROM download mode, and from then on apps are installed through Vibe Mode. Every time Claude Code flashes a new binary, the board switches to the "Vibe Mode" screen, takes the update, then restarts into the new application.

![The Vibe Mode screen, waiting for an update](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/8c45772b-5391-4be5-8e6b-a78085e57789.jpg align="center")

![Vibe Mode receiving a system update](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/e6f2e4ea-1b81-4095-8c25-972be3f89b0e.jpg align="center")

### Snake

I asked Claude Code for a Snake game as the Espressif guide suggested. It did not start from an existing example. It created a new project from the repository's blank game template, and wrote the gameplay and rendering itself: a 24×22 grid, steering by swiping or tapping beside the head, and a snake that speeds up as the score grows.

Before touching the hardware, Claude tested the game in the host simulator, which compiles the same C as the firmware. It ran headless replays scripted in JSON that covered eating, crashing, restarting, and swiping. The first firmware build succeeded, and the first successful install ran Snake correctly on the board. No game logic fixes were needed on hardware.

One nice thing I didn't expect was that Claude Code captured the device's display and showed it to me in the session. The first screenshot attempt failed because the blank template doesn't register a screen mirror. Claude Code found the mirror code in one of the BSP examples, copied it into the project, rebuilt, and updated the app. After that, it could see the board's screen without me looking at it.

In time, writing the game and getting a first successful build took 10 minutes. Getting it onto the board took another 25 minutes after I returned, mostly spent on the flash backup and USB dropouts.

![Snake running on the ESP-Mosaico](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/95c7f9a0-3076-4936-81df-f41b42337e73.gif align="center")

### The Light Meter, Again

To compare the two modes directly, I gave Claude Code the exact same request as the one I gave the ChatCoding test earlier:

> *"Show the light level as a bar on the screen and on the LEDs."*

Claude Code searched the BSP and found a driver for the Interaction module, `mosaico_module_interact`. The driver reads the module's ID EEPROM at 0x50, works out which slot the module is in, and maps the pins from there. Claude Code never had to pick a pin. The device log confirmed it at runtime:

```plaintext
Module identified: slot=left type=Interaction(0x16) id=0x0001 name=InteractionBoard
Interaction ready: slot=left eeprom=0x50 LDR=53 PIR=4 IR=48 KEY_L=13 KEY_R=12 WS2812=15 leds=rmt
```

It added the light meter to the Snake app: a gradient bar in the top bar of the screen, and the six WS2812 LEDs lighting up in proportion to the level. It ran a simulator check, built once, and updated the app. It started at 4:01 PM and was working on the board at 4:07 PM, in one iteration with no errors. When I covered the sensor, both the bar and the LEDs dropped.

![Snake with the light bar in the top bar, captured from the board by Claude Code](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/eeade3f4-c858-47a9-9a54-22ef85c12909.png align="center")

![The light meter: covering the photoresistor drops both the bar and the LEDs](https://cdn.hashnode.com/uploads/gql/69b0765babc0d950019d0eca/9d1724be-3fd4-4c04-b844-afe76f02f588.gif align="center")

Unlike ChatCoding, this time there is code to read. The ADC handling lives in Espressif's driver, not in code Claude Code wrote. Here is the read path from `mosaico_interact_read_inputs()`:

```c
esp_err_t ret = adc_oneshot_read(handle->adc, handle->ldr_channel, &ldr_raw);
#if CONFIG_IDF_TARGET_ESP32S31
const bool inverted = (handle->ldr_channel & 1U) == 0;
int level = inverted ? LDR_S31_ZERO_CODE - ldr_raw : ldr_raw - LDR_S31_ZERO_CODE;   /* zero code 2196 */
const int span = inverted ? LDR_S31_ZERO_CODE : LDR_S31_HIGH_CODE - LDR_S31_ZERO_CODE;
#endif
const int target_q8 = (level * 100 * 256 + span / 2) / span;
handle->ldr_filtered_q8 = (handle->ldr_filtered_q8 * 3 + target_q8 + 2) / 4;
```

The ESP32-S31 specific part is worth a look. According to the driver, even-numbered ADC channels on the S31 read inverted, and the driver corrects for that around a zero code of 2196. The photoresistor sits on GPIO53, ADC channel 3, so it is not inverted. An agent would not guess this, and it didn't have to. It was already in the BSP.

Claude Code's own code is short. It opens the module, reads the level in a FreeRTOS task every 100 ms, and turns it into a 6-LED bar:

```c
mosaico_interact_config_t config = MOSAICO_INTERACT_DEFAULT_CONFIG();
config.led_brightness = meter->config.led_brightness;            /* 48 */
mosaico_interact_open(&config, &meter->module);                   /* auto slot */
...
mosaico_interact_inputs_t inputs;
if (mosaico_interact_read_inputs(meter->module, &inputs) != ESP_OK) { close_module(meter); continue; }
atomic_store(&meter->level, inputs.light_level > 100 ? 100 : inputs.light_level);
...
const uint8_t lit = (uint8_t)((level * 6 + 50) / 100);
if (lit == meter->leds_lit) return;                       /* only write on change */
mosaico_interact_rgb_t frame[6] = {0};
for (uint8_t i = 0; i < lit; ++i) frame[i] = LED_COLORS[i];
if (mosaico_interact_led_write(meter->module, frame, 6) == ESP_OK) meter->leds_lit = lit;
```

If the module is missing, the task retries every 3 seconds, and the screen shows "NO SENSOR". If a read fails, it closes and reopens the module.

## ⚖️ ChatCoding vs VibeCoding

The short version: working through Claude Code was a completely different, and much better, experience than chatting with the device. Here's my breakdown:

|  | ChatCoding | VibeCoding |
| --- | --- | --- |
| Where the agent runs | On the board, with the LLM in the cloud | Claude Code on my laptop |
| Model in my test | Factory keys, then DeepSeek V4 Pro | Claude Opus 5.5 |
| Setup | Wi-Fi, Telegram bot token, optional API key | ESP-IDF install (about 7 min), USB, download mode |
| Light meter result | Nothing working after about 2 hours | Working on the first try in about 7 minutes |
| Finding the hardware | Guessed from an I2C scan, and got it wrong | Read the BSP driver. The module identified itself through its EEPROM |
| Code you can read | No | Yes, ESP-IDF C in a normal project |
| Pain points | Long waits with the factory keys, hardware discovery, session storage limits | USB dropouts in download mode, toolchain setup |
| Who it is for | Trying the board with no PC or toolchain | Developers who want to build and keep the code |

The models weren't the same. I used a frontier model in VibeCoding but not in ChatCoding, so this is not a model comparison. Still, ChatCoding missed some basic things I would expect any model to get right, like which chip is on the board and which module is plugged into it.

The bigger difference was access to information. Claude Code could read the BSP source, the guidance files, and the device log. The ChatCoding agent could only probe what it could from the board at runtime, and it never got what the board already knew about the module plugged into it.

Resources likely play a part too. ESP-Claw runs its agent loop on a microcontroller. The session history lives on the device and fills up during a single request, and hardware discovery is limited to what a Lua script can probe at runtime. ChatCoding is also new, and I expect it to get better.

It also helps to see the two modes as built for different use cases. ChatCoding is for using the board as a device: asking it things, scheduling tasks, and building small behaviors on top of its skills, with no PC or toolchain involved. Expect to guide it and provide the hardware facts it cannot find on its own. VibeCoding is for developing firmware: you get a normal ESP-IDF project you can read, version, and keep extending, at the cost of installing a toolchain and reflashing the board.

## 🧭 Things I Still Want to Try

This post covers one request in each mode, and I still need to experiment more with both. Here is what I would like to try next. In ChatCoding:

*   **The on-device route.** Quick Ask, AI Create, and voice input directly on the board, without Telegram.
    
*   **Install Skill.** ESP-Claw can install additional skills. I want to see what is available and how skills are distributed.
    
*   **The built-in skills.** Remember, Plan, and Schedule. The agent also found a `light_switch` skill already on the board, with Lua scripts for a GPIO light and an LED strip. Asking it to build on that skill might have gone better than a free-form request.
    
*   **The Memory tab.** Writing the Interaction module's pinout into the agent's memory before asking for the light meter is the first thing I will try next time.
    
*   **A Claude model in ChatCoding.** ESP-Claw lists Anthropic as an LLM provider. Running ChatCoding on the same model family as VibeCoding would separate the model from the mode.
    
*   **Web chat, web search, and the other messaging channels.**
    

In VibeCoding:

*   **The MCP servers.** Connecting the ESP Pilot and Component Registry servers in `.mcp.json`, which were not connected in my session.
    
*   **The** `mosaico-ui` **and** `gsp-sim` **skills**, which Claude Code did not need for this project but are worth a look.
    
*   **Restoring the factory firmware** from the flash backup, to go back to ChatCoding.
    

On the hardware:

*   **The camera module.** I unboxed it but did not use it in any of the tests.
    
*   **Connecting multiple Mosaicos** through the contacts and magnets around the sides.
    
*   **The rest of the Interaction module**: the PIR sensor, the IR LED, and the touch keys.
    
*   **The CoreBoard's own sensors and audio**: the IMU, the magnetometers, the microphone, and the speaker.
    
*   **A proper battery test.** My under-thirty-minutes figure came from an active agent session, not a measured run.
    

## 🦀 Where Rust Fits

Neither mode involves Rust today. ChatCoding runs Lua on top of Espressif firmware, and VibeCoding generates ESP-IDF C. On the Rust side, `esp-hal` lists the ESP32-S31 as supported but in early development (target `riscv32imafc-unknown-none-elf`), and there is no Mosaico board support crate yet.

What I find interesting is that the VibeCoding template is a blueprint for what a Rust version would need. Take its pieces one at a time:

*   **A board support crate.** The agent needs to know which pin drives the WS2812 chain, which ADC channel the photoresistor sits on, and how to detect the module in each slot. In Rust that is a BSP crate, the same thing we have been building step by step in the µFerris BSP series. An agent working against a well-designed BSP writes `board.read_light()`, not raw register setup. That is what happened in the C version of my light meter test: Claude Code called `mosaico_interact_read_inputs()` and never touched a pin number.
    
*   **Agent skills and guidance files.** The `CLAUDE.md` and skills files capture project conventions so the agent doesn't have to rediscover them. For Rust, this is where the `esp-hal` 1.x API, the async vs blocking choice, and the "build before you flash" discipline would live.
    
*   **Tooling the agent can drive.** `espflash` and `probe-rs` already cover flashing and monitoring, so the build-flash-test loop carries over.
    

A Rust compiler is also a stricter reviewer than a C compiler. In a loop where the agent iterates until the build passes, the type system catches a class of mistakes before anything reaches the board. That is the experiment I want to run next, once `esp-hal` support for the S31 matures.

## ✅ Conclusion

The ESP-Mosaico is a well-built board. The display is clear, the modules fit well, and the Interaction module identified itself as soon as the firmware looked for it.

The two programming methods gave very different results in my test. ChatCoding is the easier start: no toolchain, just Wi-Fi and a chat app. But at least in my first attempts, it did not get past the question of what hardware was attached. Across two models and about two hours, it didn't produce a light meter, and on battery, the board lasted under 30 minutes. VibeCoding was a different experience. It needed a toolchain install and some patience with USB. Once it was running, Claude Code wrote Snake, tested it in a simulator, put it on the board, and added a working light meter in about 7 minutes. Much of the credit goes to the template. The guidance files, CLI, simulator, and BSP drivers gave the agent what it needed.

In the future, I want to try more tests with Rust once `esp-hal` support for the ESP32-S31 matures.

> 🚀 **If you enjoyed this post, please upvote ESP-Mosaico on Product Hunt:** **https://www.producthunt.com/products/esp-mosaico?launch=esp-mosaico** #ESPMosaico #Espressif #ProductHunt

## 🔗 Useful Links

*   ESP-Mosaico: https://mosaico.espressif.com/
    
*   **ESP-Mosaico on Product Hunt (please upvote):** https://www.producthunt.com/products/esp-mosaico?launch=esp-mosaico
    
*   Getting started guide: https://mosaico.espressif.com/guide/
    
*   Hardware user guide: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s31/esp-mosaico/user\_guide.html
    
*   VibeCoding template: https://github.com/esp-mosaico/esp-mosaico-vibe
    
*   Project ideas: https://mosaico-ideas.espressif.com
