agentleFS
puritysbpuritysb/AgentDeck/.agents/skills/agentdeck-deploy/SKILL.md

agentdeck-deploy

Skill288 starsChanged 12 days agoMITView on GitHub

Build, install, launch, and configure AgentDeck on connected Android, Apple, ESP32, Stream Deck, Ulanzi Studio, or daemon targets. Use when the user asks to deploy AgentDeck or names target devices such as pantone, crema, lenovo, iphone, ipad, macos, esp32, tc001, d200h, bridge, daemon, or plugin.

The file

Show its rules and text

We split this skill into the rules it gives an agent

20 rules. About 0 are common, 10 are distinctive, and 10 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈10

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 10

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Run before any deploy to know what's available:

    line 94
  2. Very specific:

    Crema S: No special steps needed. (Standard requestedOrientation is used.

    line 171
  3. Distinctive:

    Lenovo Tab: No special steps needed.

    line 173
  4. Distinctive:

    After uninstall→reinstall, local network permission popup appears again

    line 201
  5. Very specific:

    Prefer existing XcodeBuildMCP tools when available.

    line 202
  6. Distinctive:

    Do not add or alter App Store UI text that asks users to install or launch external tools (App Review 4.2.3 — see AGENTS.md "App Store …

    line 217
  7. Very specific:

    Use the supervisor-routed lifecycle command (.claude/rules/daemon-lifecycle.md): daemon restart rebuilds stale packages on a checkout, …

    line 221
  8. Very specific:

    If the health wait never answers, report the daemon as unverified (not stopped) and show agentdeck daemon status.

    line 234
  9. Very specific:

    After a Marketplace/DRM validation session, restore the development installation with pnpm plugin:deploy and record pnpm plugin:check …

    line 248
  10. Very specific:

    Use pnpm --filter @agentdeck/plugin-ulanzi package to prepare a package.

    line 254
  11. Very specific:

    If the daemon is holding a serial port, stop the daemon (or use the flash helper that pauses/resumes it) before flashing — see …

    line 287
  12. Distinctive:

    86 Box CH340 fallback: If PIO upload fails at high baud (chip stops responding), build separately then flash with esptool at 115200:

    line 299
  13. Distinctive:

    After flash: USB re-plug required for JTAG boards (IPS 3.5", Round AMOLED).

    line 336
  14. Very specific:

    All three must be identified by device_info before flashing because native USB port numbers change.

    line 340
  15. Very specific:

    Use the helper script or the equivalent esptool command at 115200:

    line 355
  16. Very specific:

    always flash bootloader + partitions + firmware together

    line 375
  17. Distinctive:

    if the daemon is holding the serial port, the helper script pauses it and resumes it after flash

    line 376
  18. Distinctive:

    After all deploys complete, verify each target:

    line 380
  19. Distinctive:

    Use SKIP (not connected / not in target), OK (success), FAIL (error with reason).

    line 416
  20. Distinctive:

    Build failure: Stop immediately, show error.

    line 422

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

AgentDeck Deploy

Canonical deploy procedure for AgentDeck. This file is the single source of truth — .claude/skills/agentdeck-deploy is a tracked directory symlink to this skill. Build, install, launch, and configure AgentDeck on connected targets; keep deployment scoped to what is actually connected and skip missing devices with a clear note (never fail the whole deploy because one device is absent).

Arguments / Target Names

Parse the argument string to determine target(s). Multiple targets can be combined (e.g. android ios).

ArgumentScope
(none) / allFull deploy: bridge → plugin → android → ios → macos
androidAll connected Android devices
pantone / pantone6Pantone 6 only
cremaCrema S only
lenovo / tablet / tabLenovo Tab only
iosConnected routine iOS targets (iPad Air M2 + iPhone 14 Pro Max)
iphoneiPhone 14 Pro Max only
ipadiPad Air M2 only
macos / macmacOS app only
appleiOS + macOS
esp32All connected ESP32 display boards (excludes Ulanzi TC001)
esp32-allAll ESP32 boards including Ulanzi TC001
trmnl_75TRMNL 7.5" e-ink only
nm_epd_420 / nmRockBase NM-EPD-420 only
lilygo_epd47 / epd47LilyGo T5 ePaper S3 only
ulanzi / tc001Ulanzi TC001 LED matrix only
bridge / daemonDaemon restart only
plugin / sdStream Deck plugin only
d200h / ulanzi-pluginUlanzi Studio keypad plugin; separate from TC001 firmware
esp32_c6_147Waveshare C6-LCD-1.47; USB only, no OTA

The default all sequence above does not include ESP32 or the D200H Studio plugin. When reviewing release coverage, list those channels explicitly; when deploying, follow the requested target scope. ulanzi means TC001 firmware, whereas d200h / ulanzi-plugin means the Studio plugin. A firmware build or a plugin package does not update the installed runtime.

Device Registry

Android Devices

DeviceSerialTypeQuirks
Pantone 6AA007422R24C1300039Color e-ink (Kaleido 3, RK3566)Rotation reset on reinstall → must restore landscape. WRITE_SETTINGS permission lost on reinstall
Crema SCREMAA21W09235B&W e-ink (IWG / Qualcomm sdm660, native Onyx View API)Standard
Lenovo TabHVA095B4LCD tablet (J606F)Standard

Apple Devices

Devicedevicectl IDxcodebuild destinationType
iPad Air 11" (M2)8B71247D-A740-535E-8B2C-6FE9A196F342platform=iOS,id=00008112-001608A02ED2601EWiFi/USB
iPhone 14 Pro Max00008120-001169AA11D8C01Eplatform=iOS,id=00008120-001169AA11D8C01EWiFi/USB
macOS—platform=macOSLocal

iPhone XR is retired from routine test and deploy targets. Do not include it in all, ios, or iphone runs even if it appears in device discovery; target it only when the user explicitly requests that device.

ESP32 Boards

두 이름 층 (panel/form + 인치): friendly 는 ./scripts/flash.sh <friendly> 에 넘기는 canonical 친근명, pio env 는 pio run -e <pio env> / .pio/build/<pio env>/ 에 쓰는 실제 PlatformIO env. flash.sh 는 둘 다 받지만 pio run -e 는 pio env 만 받는다.

Boardfriendly (flash.sh)pio env (pio run -e)Serial PatternChip
86 Box (480×480)box_40box_86/dev/cu.usbserial-*ESP32-S3, CH340
IPS 3.5" (480×320)ips_35ips35/dev/cu.usbmodem*ESP32-S3, native USB
Round AMOLED (360×360)amoled_18amoled/dev/cu.usbmodem*ESP32-S3, native USB
TTGO T-Display (135×240)tft_114ttgo/dev/cu.wchusbserial*ESP32-D0WDQ6, CH340
IPS 10.1" (800×1280)ips_101ips10/dev/cu.wchusbserial*ESP32-P4 + C6
TRMNL 7.5" (800×480 e-ink)trmnl_75trmnl_75/dev/cu.usbmodem*XIAO ESP32-S3 Plus
RockBase NM-EPD-420 (400×300 e-ink)nm_epd_420nm_epd_420/dev/cu.usbmodem*ESP32-S3 N16R8, native USB
LilyGo T5 ePaper S3 (960×540 e-ink)lilygo_epd47lilygo_epd47/dev/cu.usbmodem*ESP32-S3 N16R8, native USB
T-Embed CC1101 (170×320 + encoder)t_embedt_embed/dev/cu.usbmodem*ESP32-S3, native USB
T-Display-S3-Pro (222×480)t_display_prot_display_pro/dev/cu.usbmodem*ESP32-S3, native USB
Waveshare C6-LCD-1.47 (172×320)esp32_c6_147esp32_c6_147/dev/cu.usbmodem*ESP32-C6, native USB, no OTA
Ulanzi TC001 (8×32 LED)led_8x32led8x32/dev/cu.usbserial-*ESP32-D0WD classic, CH340

Main merge trigger

The owner’s Mac uses .github/workflows/local-deploy.yml: a push to master (including a merged PR) queues the agentdeck-local-deploy runner. It runs scripts/deploy-local-main.mjs against the persistent checkout configured by AGENTDECK_MAIN_CHECKOUT, builds and tests before installation, restarts the supervised Node daemon, and deploys/verifies the Stream Deck plugin. The macOS app is replaced with a preserved backup only for development installations. An installed Contents/_MASReceipt/receipt preserves the App Store app without staging, quitting or launching it; the receipt records macOS.action: preserved-app-store rather than claiming the GUI runs the merged source. An unreadable receipt stops the deployment before app changes. A failed development swap restores/relaunches the original and removes its own stage when recovery succeeds; failed recovery leaves copies for inspection. Do not grant broader app-management permissions or replace a Store installation to make this workflow pass. The runner is a login LaunchAgent; the Mac must be awake and connected. No schedule or Codex heartbeat is involved. Runs queue while the Mac is offline. The workflow never accepts pull-request events or deploys public releases. A dirty or divergent main checkout fails without removing another session’s work. Receipts are in diagnostics/latest-main-deployment.json and logs in diagnostics/logs/local-main-*.log. A failed deployment is visible in the workflow run; inspect its log before retrying with workflow dispatch on master. Native mobile apps and firmware retain the target-specific procedures below.

Execution Steps

Output discipline. Every step below runs from the repository root (cd "$(git rev-parse --show-toplevel)"). Send long build output to a log under diagnostics/logs/ (gitignored) and show only the tail or the errors, e.g. mkdir -p diagnostics/logs; <build> >diagnostics/logs/<target>.log 2>&1 || { tail -40 diagnostics/logs/<target>.log; exit 1; }, then grep -nE 'error|FAILED' diagnostics/logs/<target>.log | head -20 if the tail is not enough. Use each tool's quiet mode: xcodebuild -quiet, gradle -q, pio run -s.

Step 0: Pre-flight — Detect Connected Devices

Run before any deploy to know what's available:

cd "$(git rev-parse --show-toplevel)"

echo "=== ADB Devices ==="
adb devices -l 2>/dev/null | grep -w device | grep -v "List"

echo "=== Apple Devices ==="
xcrun devicectl list devices 2>/dev/null | grep -E "(iPhone|iPad)" || echo "none"

echo "=== Serial Ports (ESP32) ==="
ls /dev/cu.usb* 2>/dev/null || echo "none"

echo "=== Stream Deck ==="
pgrep -x "Stream Deck" >/dev/null && echo "running" || echo "not running"

echo "=== Daemon ==="
cat ~/.agentdeck/daemon.json 2>/dev/null || echo "not running"

For macOS targets (macos, apple, all, or any run that ends in screenshots/E2E driven through System Events), also run bash scripts/macos-preflight.sh --automation --accessibility --screen-recording --json (add --firewall apple/DerivedData/Build/Products/Debug/AgentDeck.app once that app is built). Exit 2 means a grant is denied: relay each fix path to the user and stop the E2E part instead of letting a consent sheet stall it; exit 3 means it could not confirm — say so, never assume granted.

Only deploy to devices that are actually connected. Skip missing devices with a warning, don't fail. If preflight access fails, follow AGENTS.md Agent working agreements for execution-policy failures; retry only the affected command after resolving access, and do not infer device absence from an unreadable probe.

Step 1: Build (always first, unless target is bridge-only or esp32-only)

mkdir -p diagnostics/logs
pnpm build >diagnostics/logs/pnpm-build.log 2>&1 || { tail -40 diagnostics/logs/pnpm-build.log; exit 1; }

For Android targets, also build APK:

bash scripts/build-android-release.sh >diagnostics/logs/android.log 2>&1 || { tail -40 diagnostics/logs/android.log; exit 1; }

This produces dist/agentdeck-v{VERSION}.apk.

For Apple targets (ios/macos), build via xcodebuild (see Step 3/4).

Step 2: Android Deploy

For EACH connected Android device in the target set:

SERIAL="<device_serial>"
APK="dist/agentdeck-v<version>.apk"  # use the actual versioned filename from Step 1

# 1. Stop running app
adb -s $SERIAL shell am force-stop dev.agentdeck

# 2. Update in place; preserve the existing installation on every failure
if INSTALL_OUTPUT=$(adb -s "$SERIAL" install -r "$APK" 2>&1); then
  printf '%s\n' "$INSTALL_OUTPUT"
else
  INSTALL_STATUS=$?
  printf '%s\n' "$INSTALL_OUTPUT" >&2
  echo "Update failed; no uninstall was attempted. Existing app and data are retained." >&2
  exit "$INSTALL_STATUS"
fi

# 3. Launch
adb -s $SERIAL shell am start -n dev.agentdeck/.MainActivity

# 4. adb reverse for daemon connection
adb -s $SERIAL reverse tcp:9120 tcp:9120

Device-specific post-install:

Pantone 6 (after ANY install, especially after uninstall→reinstall):

# Rotation fix — reinstall resets system rotation settings (NOTE: Pantone 6 only! Do NOT run on Crema S or ordinary tablets)
adb -s AA007422R24C1300039 shell settings put system accelerometer_rotation 0
adb -s AA007422R24C1300039 shell settings put system user_rotation 1  # 1=landscape

Crema S: No special steps needed. (Standard requestedOrientation is used; do not modify system-wide user_rotation.)

Lenovo Tab: No special steps needed.

Step 3: iOS Deploy

Build once, install on multiple devices:

cd "$(git rev-parse --show-toplevel)"

# Build (one build serves both devices); a fixed derived-data path, never a DerivedData hash
xcodebuild build -project apple/AgentDeck.xcodeproj -scheme AgentDeck_iOS \
  -destination 'platform=iOS,id=00008112-001608A02ED2601E' \
  -derivedDataPath apple/DerivedData \
  CODE_SIGN_STYLE=Automatic DEVELOPMENT_TEAM=QF36NDHYHD -quiet \
  >diagnostics/logs/xcodebuild-ios.log 2>&1 || { tail -40 diagnostics/logs/xcodebuild-ios.log; exit 1; }

APP=apple/DerivedData/Build/Products/Debug-iphoneos/AgentDeck.app

For EACH iOS device in the target set:

DEVICE_ID="<devicectl_id>"
xcrun devicectl device install app --device $DEVICE_ID $APP
xcrun devicectl device process launch --device $DEVICE_ID bound.serendipity.agent.deck

Important:

  • Devices must be unlocked (passcode protected → install fails)
  • After uninstall→reinstall, local network permission popup appears again
  • Prefer existing XcodeBuildMCP tools when available; otherwise use these established xcodebuild commands

Step 4: macOS Deploy

cd "$(git rev-parse --show-toplevel)"
xcodebuild build -project apple/AgentDeck.xcodeproj -scheme AgentDeck_macOS \
  -destination 'platform=macOS' -derivedDataPath apple/DerivedData -quiet \
  >diagnostics/logs/xcodebuild-macos.log 2>&1 || { tail -40 diagnostics/logs/xcodebuild-macos.log; exit 1; }

# Kill existing → relaunch
killall AgentDeck 2>/dev/null; sleep 0.5
open -a "$PWD/apple/DerivedData/Build/Products/Debug/AgentDeck.app"

Do not add or alter App Store UI text that asks users to install or launch external tools (App Review 4.2.3 — see AGENTS.md "App Store build invariants").

Step 5: Bridge/Daemon Restart

Use the supervisor-routed lifecycle command (.claude/rules/daemon-lifecycle.md): daemon restart rebuilds stale packages on a checkout, restarts through the LaunchAgent/systemd/Scheduled Task that owns the daemon, and verifies the daemon that came up by pid and build — never background daemon start & with a fixed sleep.

agentdeck daemon restart
# Bounded health wait on the registry-resolved port (never a blind 9120 probe)
PORT=$(sed -n 's/.*"port"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p' ~/.agentdeck/daemon.json 2>/dev/null | head -n 1)
for _ in 1 2 3 4 5 6 7 8 9 10; do
  curl -fsS --max-time 2 "http://127.0.0.1:${PORT:-9120}/health" >/dev/null && break
  sleep 1
done
agentdeck daemon status

If the health wait never answers, report the daemon as unverified (not stopped) and show agentdeck daemon status.

Step 6: Plugin

A build is not a deployment: Marketplace installation can replace the source link, and an already-running process keeps its old JavaScript after a rebuild. On macOS, from the persistent main checkout, run pnpm plugin:deploy. It refuses linked worktrees and checkouts missing known origin/master changes, builds shared and plugin, preserves a replaced installation outside the host scan directory, links the source, restarts it, and requires a fresh runtime receipt matching the bundle path and SHA-256. pnpm plugin:check checks the current installation and running process without changing them. Never report success from pnpm build or a successful streamdeck link alone.

After a Marketplace/DRM validation session, restore the development installation with pnpm plugin:deploy and record pnpm plugin:check before finishing. A failed switch restores the prior installation; do not delete its backup.

Ulanzi Studio / D200H plugin

Use pnpm --filter @agentdeck/plugin-ulanzi package to prepare a package; package:install additionally installs it into Studio when deployment is in scope. Read the verification procedure and the packaging contract. Retain WASM resvg and the bundled fonts. Restart the installed plugin and verify its path, version, bundle hash and process start after replacement, then inspect actual D200H keys and reconnect behaviour. A file hash alone does not prove the running process loaded it. D200X keypad support does not imply encoder support.

Step 7: ESP32 Firmware

CRITICAL: Build and flash ONE AT A TIME — PlatformIO lock + serial port conflicts.

Ulanzi TC001 is a separate target. The esp32 target deploys connected display boards from the board SSOT, excluding TC001: 86 Box, IPS 3.5", IPS 10.1", Round AMOLED, TTGO, T-Embed CC1101, T-Display-S3-Pro, C6-LCD-1.47, TRMNL 7.5", NM-EPD-420, and LilyGo EPD47. Use ulanzi, tc001, or esp32-all to include the Ulanzi TC001. This separation exists because:

  • Ulanzi uses a different chip (ESP32-D0WD classic vs ESP32-S3)
  • Ulanzi uses FastLED matrix rendering, not LVGL — UI changes to cloud.cpp/theme.h don't affect it
  • Ulanzi requires a different flash procedure (esptool full-flash vs PIO upload)

CRITICAL: Identify boards by device_info BEFORE flashing. Port numbers change when USB hub positions change — never assume a port number means a specific board.

cd "$(git rev-parse --show-toplevel)/esp32"

# Step 1: Detect and IDENTIFY each board
for port in /dev/cu.usb*; do
  echo "=== $port ==="
  # Send device_info_request, read 1 line bounded by a perl alarm (stock macOS has no `timeout`)
  (echo '{"type":"device_info_request"}' > "$port" &) 2>/dev/null
  perl -e 'alarm shift; exec @ARGV' 2 head -n 1 < "$port" 2>/dev/null | grep -o '"board":"[^"]*"' || echo "no response"
done
# Match each port to its board name before flashing!

If the daemon is holding a serial port, stop the daemon (or use the flash helper that pauses/resumes it) before flashing — see docs/esp32.md.

Display Boards (86 Box, IPS 3.5", Round AMOLED, T-Embed CC1101, T-Display-S3-Pro)

Flash each detected display board:

# Match port to environment and flash
# run from esp32/, so the repo log dir is ../diagnostics/logs
pio run -s -e <environment> -t upload --upload-port <port> >../diagnostics/logs/pio-<environment>.log 2>&1 \
  || tail -40 ../diagnostics/logs/pio-<environment>.log

86 Box CH340 fallback: If PIO upload fails at high baud (chip stops responding), build separately then flash with esptool at 115200:

pio run -s -e box_86  # build only
BOOT_APP0=~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin
~/.platformio/penv/bin/esptool --chip esp32s3 --port <port> --baud 115200 \
  --before default-reset --after hard-reset write-flash -z \
  --flash-mode dio --flash-freq 80m --flash-size 16MB \
  0x0 .pio/build/box_86/bootloader.bin \
  0x8000 .pio/build/box_86/partitions.bin \
  0xe000 "$BOOT_APP0" \
  0x10000 .pio/build/box_86/firmware.bin

The flash size must match board_upload.flash_size (16MB since the 2026-07-05 dual-OTA migration): 8MB patches the bootloader header below the partition table and the board boot-loops on partition 3 invalid ... exceeds flash chip size. boot_app0.bin resets otadata; without it the bootloader keeps booting the older OTA slot and the board reports the previous build (both measured 2026-09-26).

Stray serial readers: with the Node daemon stopped, the macOS AgentDeck app's Swift daemon opens the boards' serial ports; two readers on one TTY show up as esptool "serial noise"/checksum failures. Quit the app (or keep the Node daemon up and use its /esp32/serial/suspend lease) before a USB write, and reopen it after.

IPS10 USB recovery: identify the current CH340 port from device_info; the fixed port in platformio.ini may be stale. Python esptool 5.3 with --before default-reset --after hard-reset and its default stub works at 460800 (measured 2026-09-26, P4 rev1.3). Do not reuse the historical no-reset/no-stub recipe. Use 16MB/DIO/40MHz, bootloader at 0x2000, partitions at 0x8000, boot_app0.bin at 0xe000, firmware at 0x10000. Browser flashing is still unverified. Suspend serial with a lease while keeping the Node daemon running.

Boards with OTA: TRMNL re-enumerates to a download node. Once a board has a dual-OTA partition table, agentdeck esp32-ota <board> -e <env> --build over WiFi is the simpler path; confirm the running build by a direct device_info read under a serial lease — the daemon's device list can keep reporting the previous build after an OTA.

After flash: USB re-plug required for JTAG boards (IPS 3.5", Round AMOLED).

Native e-ink boards

All three must be identified by device_info before flashing because native USB port numbers change. TRMNL 7.5" additionally re-enumerates to a distinct download node; choose that new node after reset. NM and LilyGo use the confirmed 115200 upload speed.

./scripts/flash.sh trmnl_75 <device_info-confirmed-port>
./scripts/flash.sh nm_epd_420 <device_info-confirmed-port>
./scripts/flash.sh lilygo_epd47 <device_info-confirmed-port>

Ulanzi TC001 (separate target)

Only flash when ulanzi, tc001, or esp32-all is specified. Skip for plain esp32 target.

Use the helper script or the equivalent esptool command at 115200:

cd "$(git rev-parse --show-toplevel)/esp32"
./scripts/flash.sh led_8x32 /dev/cu.usbserial-211110

Equivalent manual fallback:

cd "$(git rev-parse --show-toplevel)/esp32"
~/.platformio/penv/bin/esptool --chip esp32 --port /dev/cu.usbserial-211110 --baud 115200 \
  --before default-reset --after hard-reset write-flash -z \
  --flash-mode dio --flash-freq 40m --flash-size 8MB \
  0x1000 .pio/build/led8x32/bootloader.bin \
  0x8000 .pio/build/led8x32/partitions.bin \
  0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin \
  0x10000 .pio/build/led8x32/firmware.bin

Notes:

  • 460800 is not reliable on the TC001's CH340 path
  • always flash bootloader + partitions + firmware together
  • if the daemon is holding the serial port, the helper script pauses it and resumes it after flash

Verification

After all deploys complete, verify each target:

# Android: check process running
for d in AA007422R24C1300039 CREMAA21W09235 HVA095B4; do
  adb -s $d shell pidof dev.agentdeck 2>/dev/null && echo "$d: running" || echo "$d: not running"
done

# Daemon
curl -s --max-time 2 "http://127.0.0.1:${PORT:-9120}/health" | head -c 300

# Plugin / Devices
agentdeck devices 2>/dev/null

Output

Print a summary table at the end. Example:

Deploy Summary
══════════════════════════════════════════════════
 Target          Status   Details
──────────────────────────────────────────────────
 Bridge           OK      Daemon port 9120
 Plugin           OK      Runtime hash verified
 Pantone 6        OK      Installed + launched + rotation fix
 Crema S          OK      Installed + launched
 Lenovo Tab       OK      Installed + launched
 iPad Air         OK      Installed + launched
 iPhone           SKIP    Not connected
 macOS            OK      Built + launched
 ESP32            SKIP    No firmware changes
══════════════════════════════════════════════════

Use SKIP (not connected / not in target), OK (success), FAIL (error with reason). Always report which commands required approval.

Error Handling

  • Android update failure (including signing mismatch): Retain the installed app and its data, report the actual adb error/status, and stop that target. Use a build signed for its existing distribution channel. A data-destructive replacement is a separate operation requiring specific user authorization; a deployment request alone does not authorize automatic uninstall.
  • Device not connected: SKIP with warning, don't fail the whole deploy
  • Build failure: Stop immediately, show error. Don't install stale APK
  • iOS device locked: Warn "device must be unlocked" and skip
  • ESP32 upload hang: Kill after 60s timeout, suggest esptool fallback

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.