Skip to content

Developer harness

The harness is a developer loop for working on Handsy itself. From a Mac, it installs the iPhone app and updates the board’s firmware over Wi-Fi, starts a task on the phone, and brings back the run’s log and the steps it took. You don’t plug in the phone or the board along the way.

The harness is open source. It lives in harness/ on the release-1.0 branch; harness/README.md has the full setup. This page gives the overview. Questions: [email protected].

  • Slow reinstall cycles. Without it, each change means plugging the phone in to reinstall the app, unplugging the board to flash it, and plugging things back in to collect logs. The harness does all of this over Wi-Fi.
  • Testing on a real phone. Handsy works by looking at a real iPhone screen and acting on it. Simulators can’t show that. The harness runs real tasks on a real phone with the board attached, the way a user would.
  • Seeing what happened. Each run leaves a log and a step-by-step trace: what the app saw, what it decided, and what it did. The harness copies both back to the Mac so you can read them, or hand them to your coding agent.

The Mac talks only to the iPhone, over Wi-Fi, using Xcode’s devicectl. The board stays plugged into the phone. Firmware goes Mac → app → board, the same way the app’s own board update works.

For this, the board joins the Mac’s Wi-Fi network instead of opening its own hotspot (station mode). The iPhone stays on the Mac’s network and reaches the board there too.

Script What it does
harness/app.sh Build the Debug app, install it on the test iPhone, and start it.
harness/fw.sh Build the firmware, copy it into the app, and let the app install it on the board.
harness/run.sh "<task>" Start a task in the app and print how it ended.
harness/logs.sh [--runs] Copy the app’s debug.log to the Mac, and with --runs the latest run’s trace.
harness/hid.sh "…" Send raw board commands through the app (keys, typing, pointer moves), plus a screenshot.
harness/board.py One-time setup: put the board on the Mac’s Wi-Fi (net sta), or back on its hotspot (net ap).

fw.sh also has checks for the update path: --corrupt sends a damaged image (the app refuses it and the board keeps running), and --crash-test sends an image that fails to start (the board goes back to the previous firmware by itself).

  1. iPhone. Turn on Developer Mode, pair the phone with the Mac in Xcode with Connect via network, and join the Mac’s Wi-Fi. Set HARNESS_IPHONE to the phone’s name or ID.

  2. Lightning iPhones. Use a Lightning to USB 3 Camera Adapter with a charger in its Lightning port. See Lightning iPhone: camera adapter and power.

  3. Board on the Mac’s Wi-Fi. Quit the app on the iPhone, replug the board, and within 3 minutes run:

    Terminal window
    uv run harness/board.py net sta

    macOS asks to pair, then asks for the Wi-Fi name and password in a dialog. They go to the board over the encrypted link only. Open the app again.

  4. Mirror again. On the iPhone, open Control Center → Screen Mirroring → ESP32 Agent.

Terminal window
harness/app.sh # build, install, start the Debug app
harness/fw.sh # build and update the board through the app
harness/run.sh "Open Settings" # run a task, print how it ended
harness/logs.sh --runs # copy the log and the latest run to the Mac

After each firmware update the board restarts, so choose ESP32 Agent in Screen Mirroring again.

When you are done developing, put the board back on its own hotspot:

Terminal window
uv run harness/board.py net ap

The board remembers station mode across restarts and updates until you switch it back. More: iPhone joins home Wi-Fi instead of the ESP32 Agent hotspot.

  • Debug builds only. The harness commands exist only in Debug builds of the app. The App Store and TestFlight apps ignore them and install signed firmware only.
  • Updates are checked. Even in Debug builds, the app checks the image’s size and checksums before sending it. A damaged image is refused and the board keeps what it has.
  • Pairing window. A new Bluetooth peer can pair only in the 3 minutes after the board powers on.
  • Secrets stay out of logs. Wi-Fi passwords are typed into a macOS dialog, sent only over the encrypted link, and never logged.
  • Trusted networks. In station mode the board relies on your network. Use it only on a trusted network, and switch back with net ap outside development.

Logs and traces can include screenshots and task text. Treat them as private. For collecting logs without the harness, see Debugging & logs.