Skip to content

AgentDeck ESP32 v2.0.0

Choose a tag to compare

@github-actions github-actions released this 02 Nov 12:27
· 130 commits to master since this release
cde6a8c

AgentDeck ESP32 v2.0.0

2.0 highlights

This is the coordinated 2.0 release source. Store approval and public delivery
are recorded independently per channel. Availability follows the connected
daemon, agent and surface; the release audit in RELEASING.md
records evidence, channel applicability and unfinished acceptance.

  • Answer the actual request. Supported controllers show original question labels and descriptions, retain the request/session identity, and expose original choices or explicit one-time approval. Small Stream Deck layouts now expose NEXT for observed questions. Unsupported or unconfirmed replies are not reported as completed actions; observation-only OpenCode installations do not gain controls by being upgraded.
  • Attention that means a person is needed. Automatic Codex reviews no longer become human approval alerts. Ended, abandoned and replaced OpenCode requests are retired without treating an unreadable response as completion.
  • Keep sessions identifiable. Same-project deck labels retain unique session tags and use available name/branch hints. Ulanzi refreshes name-only changes; narrow keys keep words and recipient identity readable. Commands addressed to one session do not fall through to another focused session.
  • More capability in the native Mac daemon. Expand native agent observation, GitHub CI status enrichment, consented ICS calendar context, Pixoo aquarium loops and APME storage/retention controls. Node/Swift handovers preserve supported timeline identity, in-flight state, session pins and Pixoo settings; opt-in cold recovery retains explicit conflict choices.
  • A clearer aquarium across screen sizes. Refine Hermes' shared-shell entrance/return, crowded layouts, swimming lanes and labels on native and compact surfaces. Display sleep/wake propagation and supported Android frontlight recovery are improved.
  • Safer connections and updates. Avoid opening known foreign USB serial devices, including the LG monitor interface; respect serial flash suspension and stop. Improve Android discovery/retry/address handling, preserve an explicit Apple connection stop, contain malformed WebSocket input and connecting-socket teardown errors, and retain Android app data on failed updates.
  • Harden agent integrations. Refresh generated integration commands while preserving custom handlers and user-owned hook trust. Upgrade the CLI and native installers together and refresh enabled integrations after the corrected builds are available; security-report details remain private.
  • A consistent product presentation. Refresh the app/deck icon from one master, with identical generated exports across platforms, and introduce the whole workflow with the new English/Korean/Japanese-captioned product tour.
  • Experimental: daemon relay v1. Explicitly configured workers publish observed session metadata to a hub and accept only supported controls over the same connection. Real two-Mac Node/Swift transport/control and signed-app save/relaunch/disable are verified with synthetic sessions. Full remote-terminal operation, remote timeline/APME sync and long-running real-agent two-Mac acceptance are outside this claim. Held Claude questions retain their original options rather than becoming binary approvals (#662). Use the documented trusted-network/tunnel boundary.

CloudKit/Watch observation remains a development experiment. Dot native/local
routes and DotPreview Apple builds are not standard Store release features.
Physical e-ink optical performance and D200X friendly-name/VOICE acceptance are
not certified by the software or media checks below.

Changes by target

  • E-ink Decision faces use the displayed session's own original choices and indices, echo its question, and send genuine permissions by request ID. Replaced requests, unanswerable questions, questions exceeding the three-choice surface and outbound JSON overflow cannot submit a guessed reply.

  • Native daemon relay: keep held-question correlation in the worker's private snapshot. Remote controllers receive the original question/options without a permission request ID, so they can render and return the actual choice. Replacing an identical question still refreshes the private publication before accepting its answer; genuine permission IDs remain unchanged (#662).

  • App and plugin icons: refine the familiar aquarium, octopus, crayfish and six-key deck for clearer separation at small sizes. Apple, Android, web and full-colour deck plugin icons now come from one higher-resolution master with generated-export checks.

  • Node daemon: malformed WebSocket request input is refused on that connection. Query parsing uses a fixed base, and incoming Host values cannot turn URL parsing into an uncaught pre-authentication exception (#647).

  • Android development installation: build-android-release.sh --install retains the installed app and its private data on every failed update, reports the original adb output/status, and never automatically uninstalls it. The deployment skill follows the same rule (#646).

  • Node daemon: cancelling or replacing a connecting hardware-focus relay safely consumes the old socket's teardown error (#648). Serial discovery drops pending opens after flash suspension, stop or restart and checks the flash lease before each candidate; stale ports receive no initial writes (#649, #650).

  • Apple app: an explicit Stop Reconnecting or Disconnect remains in effect after foreground return, system wake and delayed health checks. Search Again and explicit host selection still resume connection (#651).

  • Android: discovery accepts custom ports advertised by an identified daemon; busy NSD resolution retries correctly and ends with the discovery lifetime (#652, #653). Malformed manual endpoints report an address error before replacing an existing connection (#654).

  • Stream Deck: observed OpenCode questions expose NEXT on small decks so every original choice remains reachable, retaining the selected page across unrelated relay updates (#655). Ulanzi decks redraw immediately when a session's display or project name changes (#656).

  • Apple release tooling: platform-specific builds upload only artifacts built and verified in that invocation, ignoring stale output from the other platform (#657).

  • macOS app and npm daemon: USB serial detection no longer opens a port whose USB vendor is known and is not an ESP32 serial bridge (Espressif native USB, WCH CH340/CH9102, Silicon Labs CP210x, Seeed XIAO). macOS names every CDC-ACM device cu.usbmodem…, so an LG monitor's "USB Controls" interface was opened, sent board JSON, and reset its USB-C/DisplayPort link roughly every 15–40 seconds while AgentDeck ran. Ports whose vendor cannot be resolved keep the previous pattern-only behavior.

  • Android and ESP32 e-ink: the background-work standby state (STBY n, #616) shipped in npm 1.9.5 and in the macOS app 1.9.4, and awaits each target's own delivery.

  • ESP32 WiFi provisioning: a board parked on USB serial is no longer sent the WiFi credentials it already holds on every serial reopen, lease resume and daemon restart. Each of those provisions woke a radio the board then had to park again. A provision now carries a credential id: an HMAC keyed by the pairing token, never a bare hash of the password. The board stores the id beside the credentials and reports it as device_info.wifiCredId, over USB only, and both daemons skip a board whose id matches. Boards that persist a provision (IPS10, T-Display-S3-Pro, NM-EPD-420, EPD47) now also receive changed credentials, which they never did. Older firmware and older daemons keep the old behaviour, and rotating the pairing token re-provisions each board once. Neither daemon writes WiFi credentials to a serial port before a board has identified itself on that connection. On most boards a provision now also reaches flash when it follows a failed captive-portal save; it used to be held in RAM only and lost at the next reboot.

  • ESP32 T-Embed: 16 KB of internal RAM is now held back from ordinary allocations, for the WiFi driver and the other allocations that can only use internal RAM to fall back on when routine heap churn has used up the rest. In a WiFi firmware update on T-Embed, internal RAM fell to 1.5 KB and one WiFi driver allocation failed (the transfer survived it); in an update with the reserve, none failed. That is one run each, so it is a first reading, not proof. Other boards stay as they were until each is measured with the reserve. device_info reports its size, what is free in it and how far it has been drawn down (internalReserveKb, internalReserveFreeKb, internalReserveMinKb), and the existing heap figures leave it out.

  • iOS app: connection and discovery logs no longer print the pairing token or its prefix. The macOS correction is included in the Apple 1.9.2 candidate; this iOS change awaits a separate delivery.

  • iOS app: timeline rows reuse one grouped history per render, reducing repeated classification work in busy dashboards. The macOS correction is included in the Apple 1.9.2 replacement; iOS delivery is separate.

  • ESP32 firmware: Wi-Fi provisioning acknowledgements report whether a board joined, saved the credentials for later, or failed. The corresponding Node/macOS setup routes are included in the candidates below; new firmware delivery is separate.

  • ESP32 firmware: stop mDNS before parking the Wi-Fi radio, fixing a crash on rejoining after USB reprovisioning. The responder starts again after the board has an address.

  • ESP32 IPS10: compress the ocean background without changing its pixels, reducing the measured firmware image from 99.2% to 92.4% of its OTA slot. Wake-word detection now requires a longer sustained match, and a voice turn with no speech ends after 3.5 seconds instead of 6; the voice tuning still needs physical acceptance.

Firmware for every board this repository builds. Each asset is named by the
board's canonical id — the same string the firmware reports as
device_info.board and the one agentdeck esp32-ota <target> takes, so the
file you download is the target you pass.

Board Factory image Display PlatformIO env Wi-Fi OTA Browser flash
86 Box agentdeck-86box-merged.bin 4" 480x480 ST7701 box_86 yes yes
IPS 10.1" agentdeck-ips_10-merged.bin 10.1" 800x1280 JD9365 ips10 yes no
IPS 3.5" agentdeck-ips_35-merged.bin 3.5" 480x320 AXS15231B ips35 yes untested
LilyGo T5 ePaper S3 agentdeck-lilygo_epd47-merged.bin 4.7" 960x540 grayscale e-ink ED047TC2 lilygo_epd47 yes untested
RockBase NM-EPD-420 agentdeck-nm_epd_420-merged.bin 4.2" 400x300 tri-color e-ink GDEY042Z98 nm_epd_420 no untested
Round AMOLED agentdeck-round_amoled-merged.bin 1.8" 360x360 ST77916 amoled yes untested
Seeed TRMNL 7.5" agentdeck-trmnl_75-merged.bin 7.5" 800x480 e-ink UC8179 trmnl_75 yes yes
T-Display-S3-Pro agentdeck-t_display_pro-merged.bin 2.33" 480x222 ST7796U t_display_pro yes yes
T-Embed CC1101 agentdeck-t_embed-merged.bin 1.9" 320x170 ST7789 t_embed yes untested
TTGO T-Display agentdeck-ttgo_t_display-merged.bin 1.14" 240x135 ST7789 ttgo yes yes
Ulanzi TC001 agentdeck-ulanzi_tc001-merged.bin 32x8 WS2812B matrix led8x32 yes yes
Waveshare C6-LCD-1.47 agentdeck-esp32_c6_147-merged.bin 1.47" 172x320 ST7789 esp32_c6_147 no untested

Flash over USB

Each board ships a merged factory image — one file, written at one offset,
on every chip:

esptool --port PORT write-flash 0x0 agentdeck-<board>-merged.bin

The merged image already carries the bootloader, the partition table,
boot_app0 and the application, with the flash size and mode patched into its
header. That matters: the bootloader offset is chip-specific (0x1000 on ESP32,
0x2000 on ESP32-P4, 0x0 elsewhere), and writing the application alone leaves
boot_app0 pointing at whichever slot a previous OTA selected — so the board
can come up running the OLD firmware. The loose -bootloader.bin,
-partitions.bin, -boot_app0.bin and -<board>.bin files are still
published for recovery work; prefer the merged image.

manifest.json carries the same facts in machine-readable form (offsets,
sha256, per-board reset/baud settings). SHA256SUMS.txt covers every binary.

Update over Wi-Fi

agentdeck esp32-ota <board> --firmware agentdeck-<board>.bin

The board must already be provisioned and connected to the daemon over Wi-Fi.
86box and ips_10 units flashed before 2026-07-05 may still carry a
factory/NO_OTA layout and need one USB full flash first.

Flash from a browser

5 of 12 boards are hardware-verified for browser flashing
(Chrome or Edge on desktop, via Web Serial). Boards marked untested are listed
there too, disabled, with the reason — a hidden board reads as unsupported.

Full changelog: https://github.com/puritysb/AgentDeck/blob/esp32-v2.0.0/CHANGELOG.md