GitHub Repository Dossier · 정적 분석 · 커밋 고정

phone-harness — 에이전트가 내 폰을 직접 구동한다

Claude Code·Codex 같은 AI 에이전트를 실제 iPhone(맥 iPhone 미러링)과 Android(adb)에 연결하는 얇은 파이썬 하네스. 탈옥도, Xcode도, 폰에 설치하는 앱도 없다. 저장소 전체(20파일 · 3,721줄)를 커밋 고정 상태로 전수 정독한 결과다.

목차
  1. 출처와 신뢰 등급
  2. 읽기 전에 (10분 가이드)
  3. 채택 판단
  4. 실제 구현
  5. 아키텍처
  6. 온보딩 (실행하지 않음)
  7. 정독 범위
  8. 유지보수 신호
  9. 보안 · 프라이버시
  10. 라이선스
  11. 주장 검증 원장
  12. 원문 링크 원장
  13. 수집 한계
01 · Provenance

출처와 신뢰 등급

이 문서의 모든 주장은 아래 단일 커밋에 고정된 저장소 상태와, 캡처 시점의 GitHub·PyPI API 응답만을 근거로 한다. 코드는 한 줄도 실행하지 않았다 (설치·빌드·테스트·import 전부 없음).

저장소
github.com/ShawnPana/phone-harness
분석 커밋 (고정)
47f37a6dd5baae9f10f16e21e50a6898ee42cd22 (main, 캡처 전후 드리프트 없음)
루트 트리
b32cedef5441a721026bd16f5100a6f627a9596f
캡처
2026-08-24 03:22–03:28 UTC · bare git + GitHub REST (인증) · capture-id 6df62909-cd29-444a-aa5d-f83b85c72c91
방법
정적 전수 정독 — substantive 20파일 3,721줄 전부, 체크아웃·실행 없음
증거 묶음
공개 증거 인덱스 · 딜리버리 리시트
Evidence trust B
Implementation confidence high
Runtime confidence unknown
Maintenance coverage medium
Security / privacy confidence medium

B인 이유: 불변 식별자 고정 + 완전한 인벤토리 + 선정 파일 전수 정독까지 갖췄지만, 정적 분석의 천장에 걸린다 — 실기기 동작은 미검증(runtime unknown)이고, 의존성·코드 스캔 상태는 API가 거부(403)해 알 수 없다.

02 · Before You Read

읽기 전에 — 10분 가이드

핵심 질문 하나

"에이전트에게 내 실제 폰의 손과 눈을 쥐여주는 가장 얇은 방법은 무엇이고, 그 대가로 나는 어떤 통제를 잃는가?"

멘탈 모델

폰을 하나의 화면 좌표 공간으로 환원한다: 눈 = 스크린샷 + OCR(또는 접근성 트리), 손 = 좌표 탭/키 입력. iOS와 Android의 물리적 차이(비디오 스트림 vs adb)는 전부 send(op) 한 개의 어휘 뒤에 숨는다. DOM이 없으므로 검증도 스크린샷이 곧 진실이다.

권장 읽기 순서

  1. 채택 판단 — 나에게 필요한 물건인지 3분 안에 결정
  2. 아키텍처 — transport 한 개 이음매의 설계를 이해
  3. 보안 · 프라이버시 — 프롬프트-규칙과 코드-강제의 경계 (이 문서의 가장 중요한 발견)
  4. 실제 구현 — 코드가 실제로 하는 일, 전 주장 file:line 인용 (README는 번역하지 않는다 — 소스가 SSOT)

선행 개념 (모르면 막히는 것만)

  • iPhone 미러링 — macOS Sequoia+가 아이폰 화면을 맥 창으로 띄우고 마우스·키보드를 터치로 전달하는 기능. 이 창은 비디오 스트림이라 접근성 트리가 없다.
  • adb — Android Debug Bridge. USB/Wi-Fi로 폰에 직접 명령(screencap, input tap)을 보내는 공식 도구.
  • 접근성 트리 — OS가 화면 요소를 텍스트+좌표로 보고하는 구조. Android엔 있고(uiautomator), 미러링 창엔 없다 — 그래서 iOS 쪽은 OCR이 대신한다.

점검 질문 3

  1. iOS 백엔드는 왜 접근성 트리 대신 Vision OCR을 쓰는가? 그 결과 screen.textsource 필드는 왜 필요한가?
  2. "PIN을 절대 입력하지 않는다"는 규칙은 iOS와 Android에서 각각 어떤 방식으로 지켜지는가 — 코드인가 프롬프트인가?
  3. 붙여넣은 텍스트가 맥 클립보드에 남는 것은 버그인가 설계인가? 저자가 복원을 기본값으로 하지 않은 이유는?

예상 소요: 요약+판단만 10분 · 완독 35–45분

03 · Adoption Verdict

채택 판단

Executive Summary

무엇: 에이전트(Claude Code/Codex)가 사용자의 실제 폰을 구동하게 하는 ~3.7천 줄짜리 파이썬 하네스. iPhone은 맥의 미러링 창을 OCR로 읽고 CGEvent로 두드리며, Android는 adb로 직접 만진다. 폰엔 아무것도 설치하지 않는다.

왜 주목: 공개 2주 남짓에 스타 1,997개. "제일 얇은 층으로 실기기를 잡는다"는 설계 취향이 일관되고, 코드 주석이 실패 경험(안 되는 것들)을 이례적으로 정직하게 기록한다.

경계할 것: 안전 규칙 대부분이 프롬프트 규칙이지 코드 강제가 아니다. 테스트 0개, 메인테이너 1인, 비공개 API(SkyLight) 의존. 본질적으로 "임의 코드로 내 폰을 조작하는 표면"을 여는 도구다.

채택하라 — 다음 경우라면

본인 폰으로 개인 자동화·에이전트 실험을 하고, 도구가 하는 일을 코드 수준에서 직접 읽고 감수할 수 있는 개발자. "폰 자동화 = Appium/WebDriverAgent 무게"라는 통념에 지친 사람에게 특히 신선하다.

보류하라 — 다음 경우라면

팀/프로덕션 QA 파이프라인용 기기 자동화가 필요한 경우(테스트·CI·멀티 디바이스·계약 안정성 전무), 또는 타인의 기기·민감 계정이 물린 폰을 다루는 경우(동의 게이트가 코드로 강제되지 않음).

대안 대비 위치

도구접근대가
phone-harness미러링 창 OCR + adb, 폰 무설치iOS는 픽셀 수준 인식뿐, 비공개 API, 1인 프로젝트
Appium/XCUITest공식 테스트 스택, 요소 트리WebDriverAgent·프로비저닝의 무게, 에이전트 루프엔 과체중
클라우드 디바이스 팜관리형 실기기비용, 내 폰·내 계정이 아님
04 · What the Code Actually Does

실제 구현 — 20파일 전수 정독 결과

README의 문장이 아니라 코드가 하는 일이다. 소스가 SSOT이고 README는 주장일 뿐이므로, 이 섹션의 모든 항목은 고정 커밋 47f37a6의 파일을 직접 읽고 file:line으로 인용한다 (경로 접두 src/phone_harness/ 생략).

엔트리포인트 → op 디스패치: 체인 전체

"에이전트가 폰을 만진다"의 실제 코드 경로는 다섯 홉이다.

  1. 진입run.py:49-57: 서브커맨드가 아니면 stdin 전체를 읽어 exec(code, g)ghelpers 모듈의 밑줄 없는 이름 전부(run.py:55). 사용법 자체가 "임의 파이썬 실행"이다.
  2. 헬퍼 네임스페이스helpers.py:514-528: import 시점에 agent-workspace/agent_helpers.py를 자동 로드해 같은 네임스페이스에 합친다. 에이전트가 써넣은 코드가 다음 실행부터 표준 어휘가 된다.
  3. op 어휘transport.py:87-97: OP_NAMES 25종 — screen 5 · input 6 · nav 3 · apps 3 · session 4 · focus 2 · tree/raw 2.
  4. 디스패치transport.py:113-117: Backend.send(op)op_screen_capture식 메서드명으로 바꿔 호출하고, 메서드가 없으면 Unsupported를 던진다(transport.py:79-84). 능력 목록이 따로 없는 이유다.
  5. 백엔드 선택transport.py:128-143: connect(platform)이 인자 → PHONE_HARNESS_PLATFORM → config → 기본 ios 순으로 결정해 IPhone/Android 객체를 반환한다(전역 설치 아님 — 한 스크립트가 기기 두 대를 동시에 잡을 수 있다, transport.py:133-135).

iOS 경로: 비디오 스트림을 더듬는 기술

  • 창 찾기mirror.py:27-74: 미러링 창을 지역화된 kCGWindowOwnerName이 아니라 소유자 프로세스 PID(kCGWindowOwnerPID, mirror.py:51)로 찾는다 — 비영어 맥에서 창 이름이 번역돼도 동작(mirror.py:36-42). 크기 필터도 없앴다: Stage Manager가 창을 38×130으로 "주차"해두는 버그(#8)를 겪은 흔적(mirror.py:62-68).
  • mirror.py:301-324screencapture -l <창id>로 창만 캡처하고, ocr.py:19-56이 Vision VNRecognizeTextRequest(accurate, ocr.py:28-29)로 모든 문자열의 박스를 얻어 좌하단 원점 정규화 좌표를 화면 좌표계로 뒤집고(ocr.py:44-47) 그대로 tap()에 넣을 수 있는 중심점을 반환한다(ocr.py:51-52). ios.py:75-79가 이 결과에 source="pixels"를 달아 screen.text로 내보낸다.
  • — HID 수준 CGEvent: 탭은 mirror.py:333-349(CGEventCreateMouseEventCGEventPost), 키는 mirror.py:415-421. 수정자 키는 플래그 마스크가 아니라 실제로 눌러 유지한다(mirror.py:425_holding; 미러링이 플래그를 떨어뜨림). shift 래치가 남아 1,200!<@))로 찍히던 버그를 고친 경위가 주석에 있다.
  • 붙여넣기input.text 기본값은 클립보드 붙여넣기(mirror.py:549-561). 이전 클립보드 복원은 의도적으로 기본 꺼짐: mirror.py:496-523 docstring이 복원 레이스로 직전 클립보드(URL·토큰·암호)가 폰에 새는 사고를 명시하고, 잔류를 택한 이유와 opt-in 복원(ios.restore_clipboard, mirror.py:521-523)을 기록한다.
  • 백그라운드 모드background.py:52-64가 SkyLight 비공개 프레임워크를 ctypes로 직접 열고, background.py:165-177이 yabai가 역공학한 0xf8 이벤트 레코드를 SLPSPostEventRecordTo로 프로세스에 직송한다 — 창 포커스 없이 입력. 기본 활성(PHONE_HARNESS_BACKGROUND=1, ios.py:45-46), import 실패 시 포그라운드 mirror로 폴백(ios.py:47-52).
  • 세션 상태ios.py:130-153: "연결됨"을 구조로 판별한다 — 비디오 스트림은 접근성 UI를 노출하지 않고 중간 화면(연결 버튼 등)은 노출한다(ios.py:149-150). 그리고 _session_require(ios.py:164-190)는 Connect 버튼을 대신 눌러주지 않고 예외 메시지로 사용자를 부른다("I will not tap Connect for you", ios.py:190).

Android 경로: 창이 필요 없는 쪽

  • adb 직결이라 포커스·창 개념이 없다. 눈 = adb exec-out screencap -p(android.py:265-273), 정확한 텍스트·박스 = uiautomator 접근성 트리(android.py:275-283, source="tree" confidence 1.0), 손 = input tap/swipe/text/keyevent(android.py:291-337).
  • 잠금 게이트가 코드로 존재android.py:223-240: 모든 input op가 _gate()를 먼저 호출하고(android.py:292,296,301,309,314,327), 게이트는 dumpsys로 잠금을 읽어(android.py:215-221) 잠겨 있으면 RuntimeError("I won't enter a PIN", android.py:234-239)로 거부한다. 깨우기(KEYCODE_WAKEUP)만 코드가 하고 잠금 해제는 사용자 몫. PIN 입력은 구현 자체가 없다. (iOS 쪽엔 상응하는 코드 게이트가 없다 — §9.)
  • USB 우선 → 페어링된 Wi-Fi 폰 순으로 자동 탐색(android.py:160-211), 세션 동안 설정 변경 없이 깨어 있게 유지. input text는 ASCII 한 토큰 제약이라 개행·백스페이스를 keyevent로 쪼갠다(android.py:326-337).

실행 표면 (알아야 할 사실)

  • run.py:51-57은 stdin으로 받은 임의 파이썬을 exec()한다 — 하네스의 사용법 자체가 "에이전트가 코드를 써서 폰을 만진다"이다.
  • agent-workspace/agent_helpers.py에이전트가 편집하라고 만든 파일이며 모든 스크립트 네임스페이스에 자동 로드된다(helpers.py:514-528). 예: tap_icon(label)은 홈 화면에서 라벨 탭이 무효라는 것을 배운 뒤 라벨보다 ~35pt 위(아이콘)를 탭하도록 에이전트가 적어둔 헬퍼다(agent_helpers.py:9-15).
  • 설정은 XDG 규약(~/.config/phone-harness 의도 / ~/.local/state 학습 상태)으로 분리(config.py), 원자적 쓰기, 손상 파일은 경고 후 기본값 — 작지만 성숙한 습관.
05 · Architecture

아키텍처 — 이음매는 하나다

설계의 전부는 transport.py의 한 문장이다: "op는 플랫폼이 어떻게 하는지가 아니라 무엇을 의미하는지로 이름 짓는다." nav.home은 아이폰에선 비디오 스트림으로 가는 Cmd+1이고 픽셀에선 adb KEYCODE_HOME이지만, 헬퍼 층은 그 차이를 모른다.

agent (Claude Code / Codex) │ 파이썬 스크립트 (stdin) ▼ run.py ── exec, helpers 네임스페이스 주입 │ helpers.py ── 플랫폼 무지: ocr() tap() type_text() open_app() … │ transport.py ── send(op, **kw) ← 유일한 이음매 (op 25종) ├── ios.py ─ mirror.py(창·CGEvent) + background.py(SkyLight) + ocr.py(Vision) └── android.py ─ adb: screencap · uiautomator tree · input │ config.py ── 의도(~/.config) vs 학습 상태(~/.local/state) agent-workspace/agent_helpers.py ── 에이전트가 실행 중 써넣는 층

설계 결정 세 가지가 물건의 성격을 정한다

  1. 능력 목록이 없다. 백엔드는 할 수 있는 op의 메서드만 정의하고, 없는 op는 자동으로 Unsupported 예외가 된다 — "iPhone엔 Back이 없다"를 흉내 내지 않고 부재로 보고한다. 가짜 Back(엣지 스와이프 추측)은 호출자가 진짜와 구별할 수 없기 때문이라고 명시.
  2. fidelity를 필드로 노출한다. screen.text의 각 박스는 source: "pixels" | "tree"를 달고 온다 — Vision은 깨끗한 텍스트에 confidence 1.0을 주므로 신뢰도 수치로는 OCR 오독과 OS 보고를 구별할 수 없다는 이유까지 docstring에 있다.
  3. 데몬이 없다. 호출마다 창 좌표·캡처를 다시 묻는 무상태 설계. 지속해야 할 것(기본 플랫폼, 페어링된 폰)만 파일로 산다. 스크립트 하나가 기기 두 대를 동시에 잡을 수 있도록 connect()는 전역이 아니라 객체를 반환한다.
06 · Onboarding — Not Run

온보딩 — 이 분석에서는 실행하지 않았다

아래는 문서·코드가 기술하는 절차의 정적 요약이며, 우리는 설치·실행하지 않았다. 절차의 실제 동작(권한 프롬프트 타이밍, --doctor 판정)은 미검증이다.

  1. 저장소를 ~/.phone-harness에 클론하고 pip install -e . — 의존성은 PyObjC 계열(맥 전용). phone-harness가 PATH의 명령이 된다.
  2. SKILL.md를 에이전트 스킬(~/.claude/skills, $CODEX_HOME/skills)로 등록 — 에이전트가 알아서 집어 들게 하는 배포 방식.
  3. 사용자 손이 필요한 것만 사용자에게: iPhone 미러링 최초 페어링, 터미널에 손쉬운 사용 + 화면 기록 권한(후자는 터미널 재시작 후 발효). Android는 개발자 옵션 + USB 허용 또는 무선 디버깅 6자리 페어링.
  4. phone-harness --doctor가 체인을 검증하고, config set platform ios|android로 기본을 고른다.
onboarding.md의 규칙: "절대 PIN을 입력하지 않는다 · 묻지 않고 설정을 바꾸지 않는다 · 실패를 루프로 재시도하지 않는다." — 그리고 §5 데모는 사용자가 예라고 하면 폰에서 phone-harness.com을 열고 저장소에 스타를 누르는 흐름까지 안내한다 (opt-in 셀프 프로모션; §9).
07 · What We Read

정독 범위 — substantive 20파일 · 3,721줄 전수

인벤토리 26엔트리 중 blob 21개, 그중 빈 패키지 마커(__init__.py)를 제외한 20개를 전부 읽었다. 부분 정독 없음.

파일왜 읽었나
README.md139프로젝트 주장 원천 — §11 원장·§4 대조 입력 전용, 완역하지 않음 (§12)
SKILL.md에이전트-대면 사용 계약 · 동의 규칙의 원문
install.md100설치 경로 · 권한 · "PIN 금지" 규칙
onboarding.md60최초 실행 흐름 · 부작용 경계 · 스타 데모
LICENSE · pyproject.toml · .gitignore라이선스 게이트 · 의존성/엔트리포인트 · 위생
.github/workflows/publish.yml38유일한 CI — PyPI trusted publishing
phone-harness (런처)4레포 루트 실행 shim
agent-workspace/agent_helpers.py23에이전트 편집 층 — 자동 로드 표면
src/phone_harness/run.py · admin.pyexec 표면 · --doctor 권한 진단
android.py (최대 모듈)adb 전체 · 잠금 게이트 · 페어링 · awake
ios.py · mirror.py · background.py · ocr.py207+563+339+57아이폰 경로 전체: 세션 판별 · CGEvent · SkyLight · Vision
transport.py · helpers.py · config.py144+—+280이음매 · 프리미티브 · 설정/상태 분리

파일별 object id·sha256·줄수 원장은 공개 증거 인덱스의 selected-blobs 원장에 있다.

08 · Maintenance Signals

유지보수 신호 — 2026-08-24 관측

1,997stars (공개 17일차)
184forks
1contributor — 버스 팩터 1
0자동화 테스트
11.3h이슈 첫 응답 실측 (#17)
42%커뮤니티 헬스 스코어
  • 속도의 프로젝트다. 2026-08-07 생성 → 08-17/08-18 릴리즈 2회(0.1.0, 0.2.0) → 08-21 마지막 push. 전 커밋 66개가 전부 ShawnPana — 100% 단독 저작.
  • 태그 4 ≠ 릴리즈 2. 0.1.10.1은 태그만 있고 GitHub 릴리즈가 없다. 그런데 0.1.1은 PyPI에는 올라갔다(08-17) — 릴리즈 노트 규율보다 배포 속도가 앞서는 단계.
  • 유일한 CI는 배포다. 워크플로 런 2회 모두 publish(성공). 테스트·린트 CI가 아예 없으므로 "CI green"은 품질 신호가 아니다.
  • 이슈: 열림 7 · 닫힘 3 (샘플). 첫 응답 실측: #17 생성(08-10 17:41Z) → 메인테이너 답변(08-11 04:58Z) = 11.3시간. 다만 #22와 #3은 메인테이너가 아닌 제3자(kri-ruj, Petrusreno)가 답했다 — 커뮤니티가 메인테이너보다 빨리 움직이는 구간이 있다.
  • PR이 가장 큰 경고다. 샘플 30건 중 머지 14건은 전부 메인테이너 본인 PR이고, 외부 기여자 PR 13건(7인)은 모두 미머지 상태로 열려 있다. 외부 기여 수용 이력이 아직 0이다.
  • 커뮤니티 문서 42%: license+readme만 있고 CONTRIBUTING·행동강령·이슈 템플릿 없음.
  • 외부 확인: PyPI에 phone-harness 0.2.0 라이브, project_urls가 저장소·phone-harness.com을 가리킴 — README의 배포 주장과 일치.
09 · Security · Privacy

보안 · 프라이버시 — 프롬프트 규칙과 코드 강제의 경계

이 도구의 위험 평가에서 가장 중요한 축은 "안전 규칙이 어디에 사는가"다. 정독 결과, 코드로 강제되는 게이트는 Android 잠금/PIN 거부 하나이고 나머지는 전부 에이전트가 지키기를 기대하는 프롬프트 문장이다.

안전 규칙사는 곳강제 수준
잠긴 Android 폰은 구동 거부, PIN 입력 코드 부재android.py:223-240 (전 input op가 _gate() 경유)코드 강제
"PIN·암호는 절대 입력하지 않는다" (iOS 포함)SKILL.md:109 · install.md:96 · onboarding.md:56프롬프트 — iOS엔 감지·차단 코드 없음 (C003)
"바깥으로 나가는 행동(발신 등) 전에 멈추고 묻는다"SKILL.md:120-124 (Consent 절)프롬프트 — input.text/tap 코드엔 발신 검사 없음 (C004)
"묻지 않고 설정을 바꾸지 않는다 · 재시도 루프 금지"onboarding.md:56프롬프트
Connect 버튼은 대신 누르지 않는다 (폰 연결 = 사용자)ios.py:164-190 (_session_require)코드 강제 (예외 발생)

구조적 위험

  • 실행 표면: run.py는 stdin의 임의 파이썬을 exec()하고, agent_helpers.py는 에이전트가 편집하는 코드가 자동 import된다. 이건 결함이 아니라 제품 정의지만 — 하네스를 설치한 순간 "에이전트가 쓰는 코드 = 내 맥과 폰에서 도는 코드"가 된다.
  • 클립보드 잔류: 폰에 타이핑한 텍스트가 맥 클립보드에 남는다(기본). 복원-레이스로 이전 클립보드가 폰에 새는 사고보다 잔류가 낫다는 문서화된 트레이드오프. 민감 텍스트를 하네스로 입력한다면 알아야 한다.
  • 비공개 API 의존: 백그라운드 모드는 SkyLight 역공학 호출이다. macOS 업데이트가 언제든 깨뜨릴 수 있고, Apple 관점에서 지원되지 않는 표면이다.
  • 권한의 무게: 터미널에 손쉬운 사용+화면 기록을 준다 = 하네스가 아니라 그 터미널에서 도는 모든 것이 화면을 읽고 입력을 합성할 수 있게 된다.
  • 셀프 프로모션 데모: 온보딩 §5가 (동의 시) 사용자의 폰으로 저장소에 스타를 누르게 한다. opt-in이 명시돼 있지만, "에이전트가 내 계정으로 하는 외부 행동"의 첫 사례가 프로젝트 자신의 스타라는 점은 알고 시작하는 게 좋다. 스타 1,997개 중 이 경로의 비중은 알 수 없다.
  • 알 수 없음(unknown): Dependabot 알림·코드 스캔 상태는 API 403으로 확인 불가 — 0건이라는 뜻이 아니다. 취약점 공고는 0건(공개 API 기준).
Static-only Receipt

이 분석은 다음을 하지 않았다: checkout · worktree · 의존성 설치 · build · test · run/import · 컨테이너 · git hooks · submodule · LFS · filter · textconv. 따라서 런타임 신뢰도는 unknown이 정직한 값이다.

10 · License

라이선스

라이선스
MIT — Copyright (c) 2026 shawn pana (LICENSE 원문 + GitHub API spdx_id 이중 확인)
허용
사용·복제·수정·재배포·상용 이용. 이 문서의 코드·문서 발췌 인용은 MIT가 명시적으로 허용하는 범위다 (저작권 고지 유지). README 완역은 라이선스가 아니라 산출 계약상 하지 않는다 (§12).
주의
보증 없음(AS IS). 비공개 API 사용에 따른 OS 호환성 책임은 사용자에게 있다.
게시 판정
공개 저장소 + MIT + 민감정보 없음 → allow
11 · Claim Ledger

주장 검증 원장 — 20건

README·SKILL의 주장과 정독 발견을 대조했다. 정적 분석이므로 실행 관측(execution-observed) 증거는 0건 — "supported"도 "코드가 그렇게 짜여 있음"이지 "실기기에서 그렇게 동작함"이 아니다. 전체 원장(JSON)은 증거 인덱스에 있다.

#주장판정근거 요지
C001에이전트가 실제 폰을 직접 구동 (iOS 미러링 / adb)지지구현 경로 전체 존재; 실행 미검증
C002iOS·Android가 하나의 op 어휘로 통일지지transport.py op 25종 + 디스패치
C003하네스는 절대 PIN을 입력하지 않는다부분 지지Android는 코드 게이트, iOS는 프롬프트 규칙뿐
C004외부로 나가는 행동 전에 멈추고 묻는다부분 지지프롬프트에만 존재 — 코드 enforcement 없음
C005run.py는 stdin 임의 코드를 exec한다지지코드 확인 (문서엔 절반만 명시)
C006agent_helpers.py는 에이전트 편집 + 자동 실행지지파일 헤더 + import 경로 확인
C007클립보드 잔류는 의도된 트레이드오프지지mirror.py 주석 + opt-in 설정
C008백그라운드 모드: 포커스 없이 SkyLight로 구동부분 지지구현 존재; 효과 수치는 저자 자기보고
C009Vision OCR 좌표를 그대로 탭에 쓸 수 있다지지ocr.py 좌표 변환 확인
C010미러링 창을 PID로 찾는다 (비영어 맥 대응)지지mirror.py 확인
C011PyPI에 0.2.0 배포됨지지PyPI API 외부 확인
C012OIDC trusted publishing (토큰 없음)지지publish.yml 확인
C013자동화 테스트 0개지지트리 전수 대조
C014단일 메인테이너 (66/66 커밋)지지contributors + 전체 히스토리
C015외부 PR 13건 미머지, 머지는 전부 본인 PR지지pulls API 샘플 30건
C016의존성·코드 스캔 보안 상태알 수 없음API 403 — 0건 단정 불가
C017온보딩 데모가 opt-in으로 스타를 누르게 한다지지onboarding.md §5 확인
C018MIT 라이선스지지LICENSE + API 이중 확인
C019릴리즈 2 ≠ 태그 4 (0.1.1은 PyPI만)지지releases·tags·PyPI 삼중 대조
C020공개 2주에 스타 ~2천지지repo 메타데이터
12 · Authored Links — No Translation

원문 링크 원장 — README는 완역하지 않는다

이 도시에는 저장소 루트 README의 한국어 완역을 싣지 않는다 (2026-08-24 산출 계약 개정). 소스 코드가 SSOT이고 팩트이며, README는 저자의 주장이다. README의 문장들은 §11 주장 검증 원장의 입력과 §4 코드 실증의 대조 대상으로만 썼고, 완역이 차지하던 지면은 file:line 코드 인용에 재배정했다. 원문이 필요하면 고정 커밋의 README.md(blob a9d337c, 139줄) 자체를 읽어라 — 사본은 공개 증거 번들에 있다.

README가 저작한 링크 5개는 원문 문맥과 함께 여기 보존한다 (occurrence 원장과 1:1; 저장소 내부 링크는 커밋 고정 주소).

  1. README 1행 표제 — 프로젝트 공식 사이트 phone-harness (이 분석에서는 방문하지 않았다 — §13).
  2. "설정 프롬프트" 문맥(README 35행) — 에이전트가 사용자를 안내하는 최초 실행 절차 onboarding.md — PIN 금지·설정 변경 금지 규칙과 opt-in 스타 데모가 사는 곳 (§6·§9).
  3. 권한 트러블슈팅 문맥(README 47행) — 설치·권한 레퍼런스 install.md — "하네스는 절대 PIN을 입력하지 않는다"의 원문(install.md:96).
  4. "사용법" 문맥 — 에이전트-대면 사용 계약 SKILL.md — Consent 절(SKILL.md:120-124)이 C004의 유일한 실체다.
  5. 같은 문단의 스킬 등록 문맥 — install.md (occurrence 3과 동일 대상) — phone-harness skill이 스킬 본문을 출력해 에이전트가 스스로 집어 들게 하는 배포 방식.

README의 실질 내용(무엇을·왜·한계)은 이 문서의 §4·§5·§6이 코드 대조와 함께 담고 있다 — 번역본이 아니라 검증본이다.

13 · Coverage & Limits

수집 한계 — 이 문서가 모르는 것

  • 정적 분석 천장: 코드를 실행하지 않았으므로 "실기기에서 실제로 동작한다"는 어떤 주장도 이 문서는 증명하지 못한다. README의 동작 수치(플릭 효과 등)는 저자 자기보고다.
  • API 샘플 경계: 이슈·PR·커밋은 per_page=30 단일 페이지 샘플이다 (커밋 전체 히스토리 66건은 bare git으로 완전). 이슈 코멘트는 대표 3건(#17·#22·#3)만 열었다.
  • 거부된 엔드포인트: Dependabot 알림·코드 스캔 API가 403 — 해당 상태는 unknown이며 0으로 간주하지 않았다.
  • SKILL.md의 세부: 스킬 본문은 정독했으나 이 문서에는 규칙·계약 수준만 반영했다 (문서 완역은 산출물이 아니다 — 소스가 SSOT, §12).
  • phone-harness.com 미방문: 공식 사이트는 열지 않았다. 링크 툴팁에 미확인으로 표기.
  • 시점 고정: 모든 수치는 2026-08-24 03:22–03:28 UTC 관측이다. 이 프로젝트는 빠르게 움직이고 있어(마지막 push 08-21) 숫자는 곧 낡는다.
정독 커버리지
substantive 20/20 파일 · 3,721/3,721줄 (100%)
인스펙션 바운드
기본 한도 내 (시간 ≤20분 창, REST 22회/90, 파일 20/30, 줄 3,721/20,000) — 확장 없음
증거
모든 API 응답·blob·원장은 sha256과 함께 공개 증거 인덱스에 고정