2026.10.13 월
ESP32 iPhone Agent: 맥 없이 에이전트에게 아이폰 맡기기
오늘의 픽: ESP32 iPhone Agent
ESP32 iPhone Agent 는 7달러짜리 ESP32-S3 보드를 아이폰에 꽂아 마우스와 키보드 역할을 맡기고, AirPlay 화면 미러링으로 화면을 읽어 비전 모델이 아이폰을 직접 조작하게 하는 오픈소스 프로덕트다.
오늘의 픽으로 선정한 이유는 맥도 개발자 계정도 없이 에이전트가 아이폰을 화면과 포인터만으로 조작하게 만들어서다.

- 출처
- GitHub
- 만든 방식
- Python, FastAPI, Arduino, UxPlay, Claude Opus 5.5
무엇이 다른가
README 에 따르면 아이폰 자동화는 대부분 XCTest 나 WebDriverAgent 를 거친다. 맥과 Xcode, 서명된 도우미 앱, 애플 개발자 계정이 필요하고, 무료 계정의 서명은 7일마다 만료된다. 접근성 트리에 의존하는 방식이라 게임 같은 앱에서는 통하지 않을 때가 있다. README 의 비교표에는 ESP32 블루투스 마우스나 HDMI 캡처 보드를 쓰는 다른 프로젝트 여덟 개가 있는데, 대부분 맥이나 별도 캡처 장비, 혹은 폰에 설치하는 앱을 요구한다.
ESP32 iPhone Agent 는 사용자가 쓰는 경로만 쓴다. 화면은 AirPlay 미러링으로 읽는다. 아이폰이 컴퓨터의 UxPlay 로 화면을 보내고 GStreamer 가 그것을 JPEG 프레임으로 바꾼다. 입력은 USB HID(운영체제가 별도 드라이버 없이 받아 주는 마우스·키보드 규격)로 넣는다. 7달러짜리 ESP32-S3 보드가 아이폰 USB 단자에 꽂혀 마우스와 키보드로 인식되고, iOS 의 AssistiveTouch 를 켜면 화면에 둥근 포인터가 생긴다. 클릭이 탭이고 드래그가 스와이프다. 보드에는 로직이 없다. Wi-Fi 로 서버에 접속해 move, click, type 같은 한 줄 명령을 받아 실행할 뿐이다. 모델은 OpenAI 호환 비전 모델이면 무엇이든 된다. 계획자가 목표와 화면으로 짧은 계획을 쓰고, 행동자가 새 스크린샷마다 다음 행동 하나를 고른다. 폰에는 아무것도 설치하지 않는다.
포인터가 상대 좌표라 서버는 포인터가 어디 있는지 알 수 없다. 그래서 탭 전에 포인터를 12 단위 흔들어 미러링 화면에서 찾아 보정하고, 행동 뒤에는 화면이 실제로 바뀌었는지 픽셀 차이로 확인해 빗나간 탭을 모델에 알린다. 같은 행동이 세 번 반복되면 다시 계획한다. 대가는 속도와 보이지 않는 화면이다. README 에 적힌 속도는 DGX Spark 두 대로 행동당 약 1.3초이고, 잠금 화면과 Apple Pay, DRM 영상은 미러링되지 않아 에이전트가 볼 수 없다. 키보드 입력은 ASCII 뿐이다. 이 아이디어로 얻는 것은, 화면과 포인터라는 사용자의 경로만 쓰면 맥도 개발자 계정도 없이 에이전트에게 아이폰을 맡길 수 있다는 것이다.
어떻게 만들었나
커밋 20개가 2026-10-12 하루에 몰려 있고 마지막 커밋은 기록 전날 밤이다. 그중 16개에 Co-authored-by 트레일러로 Claude Opus 5.5 가 적혀 있다. README 의 Quick start 첫 항목은 사용자가 아니라 코딩 에이전트에게 붙여 넣으라는 지시문이다. 보드에 펌웨어를 기록하고 UxPlay 와 서버를 설치하고 .env 를 쓰라는 내용이다. 파이썬 서버는 1,100줄 정도이고 펌웨어는 Arduino 스케치 155줄이다. 테스트는 28개다.
실행해 보니
오늘 확인한 것은 서버뿐이다. 보드도 아이폰도 없어 에이전트가 실제로 탭하는 장면은 보지 못했다. 설치는 python3 -m venv 와 pip install -e ".[dev]" 로 18초가 걸렸고, 의존성이 FastAPI, uvicorn, httpx, Pillow 네 개라 가상환경은 91 MB 다. 테스트 28개는 1.45초에 통과했다. .env 에 가짜 모델 주소를 적고 서버를 실행하니 583 ms 만에 웹 UI 가 열렸다. UxPlay 가 없어 화면 수신 스레드는 FileNotFoundError 로 종료됐지만 서버는 그대로 작동했다. 보드 프로토콜을 확인하려고 7300 포트에 접속해 ok 만 답하는 TCP 클라이언트를 만들었다. 서버는 그것을 보드로 받아들여 상태가 device true 로 바뀌었고, 웹 UI 의 첫 단계 Plug in the controller 가 초록으로 바뀌었다. 디버그 전용 /api/raw 로 ping 과 move 10 -5 를 보내자 두 줄이 그대로 클라이언트에 도착했다. 보드에 로직이 없다는 말은 맞다. 보정 없이 탭을 요청하면 409 pointer not calibrated, 화면 없이 에이전트를 시작하면 409 no phone screen 으로 거절한다. README 의 주장 세 개는 다 맞았다. 코드에서 하나 더 확인한 것은 스크린샷 비교 방식이다. 포인터가 있던 자리와 상태 표시줄을 가리고 나머지 픽셀만 세며, 체크 표시 하나 정도의 작은 변화도 여섯 점 이상이면 바뀐 것으로 친다.
status 200 after 583 ms
hidagent.device board connected from ('127.0.0.1', 50552) hello power-on 1234
hidagent.device move 10 -5 -> ok (0 ms)
"POST /api/tap HTTP/1.1" 409 Conflict

확인하지 못한 것
보드에 펌웨어를 기록하고 아이폰을 미러링해 에이전트가 계획을 쓰고 탭하는 루프는 이 환경에서 밟지 못했다. README 의 행동당 1.3초도 측정하지 못했다. 다음에 볼 곳은 phone.py 의 보정이다. 포인터를 흔들어 찾는 방식이 밝은 배경과 어두운 배경에서 모두 통하는지, 그리고 AssistiveTouch 의 포인터 속도를 바꾼 뒤 얼마나 어긋나는지다.
판정
서버는 작동한다. 명령 네 줄로 설치와 테스트가 끝나지만, 보드와 아이폰이 없는 환경에서는 에이전트가 화면을 보지도 탭하지도 못한다. 맥 없이 리눅스 한 대와 7달러짜리 보드로 아이폰을 에이전트에게 맡겨 보고 싶고, 행동마다 1초 넘게 기다려도 되는 경우에 맞는다. 잠금 화면이나 결제처럼 미러링되지 않는 화면을 거쳐야 하는 일에는 이 프로덕트가 맞는 선택이 아니다. 그런 화면은 에이전트에게 보이지 않는다.
시작하기
git clone https://github.com/onehumanbeing/esp32-iphone-agentcd esp32-iphone-agent/server && python3 -m venv .venv && .venv/bin/pip install -e .cp .env.example .env && set -a && . ./.env && set +a && .venv/bin/python -m hidagent
- 필요한 것
- Python 3.10 이상 · XIAO ESP32S3 보드(약 7달러)와 arduino-cli, ESP32 코어 3.x · UxPlay(AirPlay 수신기)와 GStreamer · OpenAI 호환 비전 모델 API. 클라우드 API 나 직접 운영하는 서버 · 아이폰의 AssistiveTouch 설정과 2.4 GHz Wi-Fi
- 비용
- MIT 라이선스, 무료. 비용은 보드 약 7달러와 비전 모델 API 사용료다. README 가 개발에 쓴 로컬 모델 구성은 NVIDIA DGX Spark 두 대다.
보드에는 hardware/flash.sh 로 펌웨어를 기록하고, 서버는 http://<컴퓨터 IP>:8890 에서 웹 UI 를 연다. 오늘은 보드와 아이폰 없이 서버만 실행했다.
실행해서 확인한 절차다.
다시 보기
7일, 30일, 90일 뒤에 이 프로덕트가 살아 있는지, 무엇이 바뀌었는지, 반응은 어떤지 다시 확인해서 여기에 적는다.