wendy-lite
SKILL.md
Wendy Lite
Wendy Lite is a WebAssembly (WASM) runtime firmware for ESP32-C6 microcontrollers. It enables developers to write apps in C, Rust, Swift, Zig, TypeScript, or WAT, compile them to WASM, and run them on the device with full hardware access.
Key Concepts
- WAMR Runtime: Uses WebAssembly Micro Runtime to execute WASM binaries
- Host Imports: WASM apps import functions from the
"wendy"module to access hardware - Callback System: Async events (GPIO interrupts, timers, BLE) dispatched via exported
wendy_handle_callback - Flash Persistence: WASM binaries stored in flash partition
wasm_a(2MB), auto-loaded on boot - Multi-language: Apps can be written in C, Rust, Swift 6.0+, Zig, TypeScript, or raw WAT
Project Structure
wendy-lite/
├── main/wendy_main.c # Firmware entry point, WASM lifecycle manager
├── components/
│ ├── wendy_wasm/ # WAMR integration (load, run, stop modules)
│ ├── wendy_hal/ # Hardware: GPIO, I2C, RMT, NeoPixel, Timer
│ ├── wendy_hal_export/ # Registers HAL as WASM host imports
│ ├── wendy_usb/ # USB CDC wire protocol for app upload
│ ├── wendy_wifi/ # WiFi station + HTTP binary download
│ ├── wendy_ble_prov/ # BLE WiFi provisioning ("Wendy-XXXX")
│ ├── wendy_cloud_prov/ # Cloud device certificate provisioning
│ ├── wendy_callback/ # Async ISR-safe event dispatch (max 32 handlers)
│ ├── wendy_storage/ # NVS key-value storage for apps
│ ├── wendy_uart/ # UART serial communication
│ ├── wendy_spi/ # SPI bus master
│ ├── wendy_sys/ # System: reboot, uptime, device ID
│ ├── wendy_otel/ # OpenTelemetry: logs, metrics, traces
│ ├── wendy_ble/ # BLE peripheral/central (optional)
│ ├── wendy_net/ # TCP/UDP sockets, DNS, TLS (optional)
│ ├── wendy_wasi_shim/ # WASI compatibility layer
│ ├── wendy_safety/ # Memory safety
│ └── wendy_app_usb/ # USB from WASM app perspective (optional)
├── wasm_apps/ # Example WASM applications
│ ├── include/wendy.h # App API header (all host imports)
│ ├── Makefile # Build system for all app languages
│ ├── blink/ # C: GPIO LED blink
│ ├── i2c_sensor/ # C: BMP280 I2C sensor reader
│ ├── swift_display/ # Swift 6.0+ embedded WASM app
│ ├── rust_blink/ # Rust WASM app
│ ├── zig_blink/ # Zig WASM app
│ └── wat_blink/ # Raw WebAssembly Text
├── partitions.csv # Flash layout (nvs, factory, wasm_a, storage)
├── sdkconfig.defaults # ESP-IDF + WAMR + feature flags
└── diagram.json # Wokwi simulator circuit
Writing WASM Apps
C (Recommended for Getting Started)
#include "wendy.h"
void _start(void) {
gpio_configure(2, WENDY_GPIO_OUTPUT, WENDY_GPIO_PULL_NONE);
for (int i = 0; i < 10; i++) {
gpio_write(2, 1);
timer_delay_ms(500);
gpio_write(2, 0);
timer_delay_ms(500);
}
}
Build:
cd wasm_apps
make blink
Or manually:
clang --target=wasm32 -O2 -nostdlib -I include \
-Wl,--no-entry -Wl,--export=_start -Wl,--allow-undefined \
-o app.wasm app.c
Swift (Recommended for App Development)
Swift apps use the WendyLite Swift package from https://github.com/wendylabsinc/wendy-lite, which provides type-safe wrappers around all WASM host imports.
See references/swift-sdk.md for the complete Swift API reference, Package.swift setup, and examples.
Key points:
- Requires Swift 6.0+ with Embedded Swift support
- Uses
@_cdecl("_start")for the WASM entry point - No heap allocation — use stack-allocated tuple buffers
StaticStringonly — no runtime string construction- Cast
UnsafePointer<UInt8>toUnsafePointer<CChar>viaUnsafeRawPointerfor API calls - Build and deploy with
wendy run
Quick start:
import WendyLite
@_cdecl("_start")
func start() {
GPIO.configure(pin: 2, mode: .output)
GPIO.write(pin: 2, level: 1)
System.sleepMs(1000)
GPIO.write(pin: 2, level: 0)
}
Other Languages
| Language | Build Command | Requirements |
|---|---|---|
| Rust | make rust_blink |
rustup (not Homebrew Rust) |
| Zig | make zig_blink |
Zig 0.13+ |
| WAT | make wat_blink |
WABT (wat2wasm) |
App Requirements
- Export a
_startfunction as the entry point - Import host functions from the
"wendy"module - For async callbacks, export
wendy_handle_callback(int handler_id, int arg0, int arg1, int arg2) - Call
sys_yield()to allow callback dispatch
Hardware Access Summary
| Subsystem | Key Functions | Notes |
|---|---|---|
| GPIO | gpio_configure, gpio_read, gpio_write, gpio_set_pwm, gpio_analog_read, gpio_set_interrupt |
Supports input, output, PWM, ADC, interrupts |
| I2C | i2c_init, i2c_scan, i2c_write, i2c_read, i2c_write_read |
Bus 0 pre-initialized by firmware |
| NeoPixel | neopixel_init, neopixel_set, neopixel_clear |
WS2812 RGB LEDs via RMT |
| Timer | timer_delay_ms, timer_millis, timer_set_timeout, timer_set_interval |
Blocking delay + async callbacks |
| UART | uart_open, uart_write, uart_read, uart_set_on_receive |
Serial ports with callbacks |
| SPI | spi_open, spi_transfer, spi_close |
Full-duplex master |
| Storage | storage_get, storage_set, storage_delete, storage_exists |
Persistent NVS key-value |
| System | sys_reboot, sys_uptime_ms, sys_device_id, sys_yield |
Device info and control |
| OTel | otel_log, otel_metric_*, otel_span_* |
Structured logging, metrics, tracing |
| BLE | ble_init, ble_advertise_start, ble_gatts_*, ble_gattc_* |
Optional, disabled by default |
| WiFi | wifi_connect, wifi_status, wifi_get_ip, wifi_ap_start |
App-facing WiFi control |
| Sockets | net_socket, net_connect, net_send, net_recv |
TCP/UDP, optional |
| TLS | tls_connect, tls_send, tls_recv |
Secure connections |
| Console | wendy_print |
Output to UART + USB |
Boot & Lifecycle
- Firmware initializes NVS, WAMR pool, HAL, USB, BLE provisioning, WiFi
- WASM manager thread starts, registers all HAL exports
- Auto-loads WASM from flash partition
wasm_a(if present) - Runs WASM
_start()in dedicated thread (8KB stack) - Event loop handles: upload, run, stop, reset requests
Uploading WASM Binaries
- WiFi: HTTP download via UDP listener after WiFi provisioning
- USB CDC: Wire protocol with PING, UPLOAD (START/CHUNK/DONE), RUN, STOP, RESET messages
- Flash: Written to
wasm_apartition with 4-byte size header, persists across reboots
BLE Provisioning
Device advertises as "Wendy-XXXX" over BLE. A client can:
- Discover the device via BLE scan
- Send WiFi SSID/password via GATT characteristics
- Device connects to WiFi and starts mDNS + UDP listener
Building the Firmware
# Requires ESP-IDF (v5.x) with ESP32-C6 support
idf.py set-target esp32c6
idf.py build
idf.py flash monitor
Wokwi Simulator
The project includes wokwi.toml and diagram.json for hardware simulation without a physical board.
Memory Constraints
- WAMR pool: 229KB (pre-allocated before WiFi/BLE)
- WASM stack: 8KB, heap: 8KB
- Flash: 4MB total (1.875MB firmware, 2MB WASM, 64KB app storage)
- WiFi/PHY IRAM offloaded to flash to free ~15-25KB DIRAM
Reference Files
Load these files as needed for specific topics:
references/swift-sdk.md- WendyLite Swift package: Package.swift setup, complete Swift API reference, Embedded Swift constraints, stack buffer patterns, code examplesreferences/wasm-api.md- Complete WASM app API: all host imports, constants, callback system, per-subsystem function signatures and usage (C-level)references/firmware-config.md- ESP-IDF sdkconfig options, partition table, feature flags, memory tuning, component enable/disable
Weekly Installs
2
Repository
joannis/claude-skillsGitHub Stars
52
First Seen
11 days ago
Security Audits
Installed on
opencode2
claude-code2
github-copilot2
codex2
kimi-cli2
gemini-cli2