본문으로 건너뛰기
5분 AI.
GITHUB TRENDING SWIFT WEEKLY #4 딥다이브 · 2026-10-23 분석

open-computer-use 딥다이브
— AI의 클릭 뒤에 있는 운영체제와 안전장치

MCP 서비스

빠른 판단

무엇
앱·창·접근성 요소 관찰과 클릭·입력을 세션 검증으로 연결하는 데스크탑 MCP 서비스
이럴 때
에이전트가 데스크탑 앱을 읽고 조작하게 하면서 관찰한 대상과 실제 동작 대상의 일치를 확인할 때
입력
실행 중인 앱·창과 관찰·클릭·텍스트 입력 요청
결과
UI 상태와 세션·대상 검증을 거친 조작 결과
AI가 앱의 버튼을 누르기까지 어떤 코드가 필요할까요? open-computer-use는 접근성 트리, 화면 캡처, 입력 이벤트를 MCP 도구로 묶은 로컬 데스크톱 자동화 서비스입니다. Swift 중심의 macOS 엔진부터 Go·Python·PowerShell로 이어지는 플랫폼 경계, 오래된 화면 정보를 거부하는 검증까지 소스로 따라갑니다. 2026-10-23 GitHub 기준 ⭐2,645 · 포크 245 · Swift · MIT · 최신 릴리스 v1.1.2. 코드 해설은 커밋 43eb4b5 기준입니다.
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

AI의 판단과 운영체제의 실제 조작 사이를 연결하는 실행 도구

open-computer-use는 AI 에이전트가 데스크톱 앱을 관찰하고 조작할 수 있게 해주는 오픈소스 MCP 서비스입니다. 앱 목록을 읽고, 창의 상태를 가져오고, 버튼을 누르고, 글자를 입력합니다. 스스로 모델을 학습하거나 다음 행동을 결정하는 부분은 이 서비스의 역할이 아닙니다.

이 저장소에서 배울 핵심은 “클릭 명령” 자체보다, 지금 보고 있는 앱과 실제로 조작할 앱이 같은지 확인하는 방법입니다.

한 문장 비유

AI가 운전자라면, 이 프로젝트는 계기판과 조향 장치입니다

운전자는 어디로 갈지 판단합니다. 계기판은 현재 속도와 상태를 보여주고, 조향 장치는 그 판단을 실제 움직임으로 바꿉니다. 여기서는 AI 클라이언트가 운전자, get_app_state가 계기판, click·type_text가 조향 장치에 해당합니다.

계기판이 2분 전 화면을 보여주면 위험하듯, 자동화에서도 오래된 버튼 번호와 좌표를 믿으면 엉뚱한 곳을 조작할 수 있습니다. 그래서 상태를 읽는 코드와 상태를 폐기하는 코드가 입력 코드만큼 중요합니다.

용어
접근성 트리와 MCP
접근성 트리는 운영체제가 제공하는 “이 창에는 제목이 무엇인 버튼과 입력칸이 있다”라는 구조화된 목록입니다. MCP는 AI 클라이언트와 도구 제공자가 요청·결과를 주고받는 공통 규약입니다. 하나는 앱을 이해하는 통로이고, 다른 하나는 AI와 연결하는 통로입니다.

1-1. 한 번의 작업은 세 단계로 읽는다

  1. 관찰: 앱의 접근성 정보와 필요에 따른 스크린샷을 가져옵니다.
  2. 실행: 현재 요소 번호나 스크린샷 기준 좌표를 이용해 도구를 호출합니다.
  3. 확인: 결과 상태를 다시 읽고, 원했던 변화가 생겼는지 판단합니다.

macOS 구현에서는 packages/OpenComputerUseKit/Sources/OpenComputerUseKit/ComputerUseService.swift가 이 흐름의 중심입니다. getAppState()가 상태를 만들고, click() 등이 동작을 수행하며, actionResult()가 설정에 따라 후속 상태를 반환합니다.

// native MCP 클라이언트가 보내는 요청의 개념 예시
{"jsonrpc":"2.0","id":1,"method":"tools/call",
 "params":{"name":"get_app_state","arguments":{"app":"TextEdit"}}}

// 결과에서 확인한 현재 요소 번호를 같은 세션에서 사용한다.
// 12는 설명용 번호이며, 실제 화면에서 얻은 값으로 바꿔야 한다.
{"jsonrpc":"2.0","id":2,"method":"tools/call",
 "params":{"name":"click",
 "arguments":{"app":"TextEdit","element_index":"12"}}}

위 JSON은 구조를 읽기 쉽게 펼친 표현입니다. 이 서버의 stdio 통신에서는 요청마다 JSON을 한 줄로 직렬화하고 끝에 줄바꿈을 붙입니다. 여러 줄로 펼친 JSON을 그대로 보내면 readLine()이 메시지를 나누어 읽습니다.

같은 서비스를 두 가지 방식으로 호출할 수 있습니다. 일반 MCP 클라이언트는 네이티브 도구를 직접 호출합니다. Codex 플러그인 경로에서는 지속적인 JavaScript 실행 환경이 그 도구들을 감싸고, 모델에 js와 js_reset을 노출합니다. “도구가 2개”라는 설명과 “도구가 여러 개”라는 설명은 서로 다른 계층을 가리킬 수 있습니다.

학습 목표
AI 프로젝트를 운영체제 프로그램으로 읽기

모델 호출보다 프로토콜 파싱, 세션 상태, 트리 탐색, 좌표 변환, 권한 진단, 오류 복구를 공부하기 좋은 저장소입니다. 이 개념들은 테스트 자동화, 개발 도구, 원격 제어 프로그램에도 그대로 이어집니다.

2왜 주목받는가

화제의 배경과, 장점을 평가할 때 함께 읽어야 할 조건

2-1. 화면을 “사진”과 “구조”로 함께 다룬다

GitHub Trending Swift Weekly #4에 선정된 프로젝트로, 2026-10-23 기준 스타 2,645개와 포크 245개를 기록했습니다. README는 Codex Computer Use에서 영감을 받아 접근성 기반의 비침해적 자동화를 공개 구현했다고 설명합니다. 아래는 기능과 소스에 근거해 관심을 끌 만한 요인을 정리한 분석입니다.

첫째, 그림만 보고 좌표를 맞추는 방식에 구조화된 UI 정보를 더합니다. AccessibilitySnapshot.swift의 ElementRecord에는 역할, 제목, 값, 액션, 창 내부 위치가 담깁니다. “오른쪽 위의 파란 점”보다 “제목이 저장인 버튼”을 대상으로 삼을 근거가 생기는 셈입니다.

둘째, 사용 중인 데스크톱을 덜 방해하려는 설계가 구체적입니다. 앱을 대상으로 한 입력, 실제 포인터와 구분되는 소프트웨어 커서, 창을 별도 가상 디스플레이로 옮기는 경로가 있습니다. 다만 앱마다 접근성 지원이 다르고, 일반 복구 경로에는 활성화가 허용되는 경우도 있습니다.

셋째, 모델과 실행 엔진의 결합이 느슨합니다. 네이티브 MCP 서버와 여러 클라이언트용 설치 진입점이 있어, 하나의 AI 앱 전용 기능을 넘어 실행 도구를 재사용하는 구조를 볼 수 있습니다. 이것이 모든 클라이언트·모든 앱에서 같은 결과를 보장한다는 뜻은 아닙니다.

2-2. 무엇과 비교하면 장점이 분명해지는가

비교 대상이 프로젝트의 장점함께 볼 제약
일반 좌표 매크로요소 역할·제목·액션과 좌표를 함께 사용합니다. macOS query는 텍스트로 요소를 찾습니다.대상 앱이 접근성 정보를 충분히 제공해야 의미 기반 조작이 유효합니다.
브라우저 전용 자동화네이티브 데스크톱 앱까지 다루는 운영체제 계층이 학습 대상입니다.웹페이지 내부만 다룰 때와는 창·권한·픽셀 배율 문제의 범위가 다릅니다.
Codex 번들 도구소스를 읽고 수정할 수 있는 MIT 프로젝트이며, 직접 연결 가능한 MCP 서버를 제공합니다.공식 구현의 완전한 복제는 아닙니다. 저장소 문서는 서명·호스트 통합·세션 승인 경험의 차이를 명시합니다.
앱의 전용 API전용 API로 노출되지 않은 UI 기능까지 접근할 수 있는 통로입니다.UI 변화의 영향을 받습니다. 이 프로젝트의 서버 안내도 필요한 기능이 전용 도구에 있으면 그 도구를 우선하도록 권합니다.

Codex와의 비교 범위는 README, docs/ARCHITECTURE.md, scripts/computer-use-cli/README.md의 설명 기준입니다. 이 자료는 경쟁 제품의 성능 순위나 성공률을 측정한 벤치마크가 아닙니다.

공개 구현의 교육적 가치는 “AI가 앱을 쓴다”는 결과를 관찰·검증·실행이라는 읽을 수 있는 코드로 나눠 보여준다는 데 있습니다.

2-3. README의 도구 수와 실제 목록은 다르다

문서와 구현의 차이
macOS는 11개, Windows·Linux는 9개

README 후반은 네이티브 도구를 “9개 핵심 도구와 macOS의 query”로 설명하지만, ToolDefinitions.swift의 실제 목록에는 select_text도 있어 macOS는 총 11개입니다. Windows·Linux의 main.go는 select_text와 query를 제외한 9개를 노출합니다.

도구 이름이 같더라도 세부 옵션은 다릅니다. 예를 들어 Linux는 macOS의 sky_click 같은 전달 경로를 그대로 구현하지 않습니다. 실제 연결 시에는 해당 서버의 tools/list와 플랫폼별 오류를 기준으로 판단해야 합니다.

최신 릴리스 문서 docs/releases/github/v1.1.2.md에는 움직이는 창에 대한 커서 정렬, Linux 동작 후 상태 읽기 설정 수정, 저장소 이름 변경에 따른 링크 정리가 기록되어 있습니다. 시각적 데모 뒤에서 상태 수명과 플랫폼 차이를 계속 다듬는 프로젝트라는 점도 읽을 거리입니다.

3기술 스택 전체 지도

서버·사용자 인터페이스·배포 도구를 나누되, 웹 서비스라고 가정하지 않기

3-1. 백엔드: 로컬 네이티브 실행 엔진

여기서 백엔드는 HTTP 서버와 데이터베이스가 중심인 웹 백엔드가 아닙니다. macOS의 핵심은 OpenComputerUseKit 라이브러리와 OpenComputerUse 실행 파일입니다. 기본 MCP 전송은 표준 입력·출력이며, 앱 호스트 경로에는 로컬 소켓 통신도 사용됩니다.

계층기술·버전근거와 담당 역할
macOS 언어Swift tools 6.2Package.swift 첫 줄. 설치된 컴파일러 버전의 실측값이 아니라 패키지 도구 버전 선언입니다.
플랫폼 하한macOS 14Package.swift의 .macOS(.v14). 앱 빌드 스크립트도 macOS 14.0 타깃을 사용합니다.
화면·입력AppKit, ApplicationServices, CoreGraphics, ScreenCaptureKit운영체제 SDK입니다. 접근성 요소, 창, 이미지, 입력 이벤트를 다룹니다. 별도 패키지 버전은 선언하지 않습니다.
이미지 의존성libwebp-Xcode 1.6.0Package.swift가 exact로 고정하고 Package.resolved도 같은 버전을 기록합니다.
WindowsGo 1.22 선언 + PowerShellapps/OpenComputerUseWindows/go.mod와 runtime.ps1. UI Automation 및 Win32 호출을 연결합니다.
LinuxGo 1.22 선언 + Python 3apps/OpenComputerUseLinux/go.mod와 runtime.py. PyGObject로 AT-SPI 2.0, 선택적으로 GDK 3.0 인터페이스를 요청합니다.
MCP 프로토콜2025-03-26macOS MCPServer.swift의 초기화 응답에 적힌 버전입니다. 최신 규격 전체를 구현했다는 뜻은 아닙니다.

Package.resolved의 libwebp 고정 리비전은 2b5256c29ff4e20f2a0d5ee863b62b1a22144434입니다. WebPEncoding.swift의 losslessWebPData(for:)는 C 함수 WebPEncodeLosslessRGBA를 호출하고, defer로 WebPFree를 보장합니다. 의존성 목록과 실제 사용처를 연결해 읽기 좋은 사례입니다.

3-2. 프론트엔드: AppKit 권한 창과 커서, 그리고 코드 인터페이스

루트 package.json에는 React·Vue 같은 웹 UI 의존성이 없습니다. 이 저장소의 사용자 인터페이스는 네이티브 앱과 CLI에 가깝습니다. apps/OpenComputerUse/Sources/OpenComputerUse/PermissionOnboardingApp.swift는 AppKit 기반 권한 안내 창을 만듭니다.

용어
선언 버전, 고정 버전, 실행 환경은 서로 다르다
go 1.22는 모듈의 언어·도구 호환성 선언이고, CI가 설치하는 Go 버전과는 별개입니다. exact: "1.6.0"은 의존성 버전을 고정하는 표현입니다. “Swift 프로젝트니까 Swift만 설치하면 된다”는 식으로 이 층들을 합치면 배포 구조를 놓칩니다.

3-3. 인프라·빌드: npm은 네이티브 앱을 싣는 포장 상자

npm으로 설치된다는 사실과 실행 엔진이 JavaScript라는 사실은 같지 않습니다. 루트 package.json은 npm 게시를 막은 저장소 관리용 패키지이며, scripts/npm/build-packages.mjs가 배포용 패키지 메타데이터를 생성합니다.

항목실제 설정읽을 때의 의미
npm 런처생성 메타데이터의 Node.js >=18네이티브 바이너리를 선택하고 JS 실행 환경을 연결하는 데 필요합니다.
배포 대상macOS·Linux·Windows, 각각 arm64·x64런처는 process.platform과 process.arch를 기준으로 동봉 런타임을 고릅니다.
릴리스 작업macos-26, Node.js 24, Go 1.22.x.github/workflows/release.yml의 패키지 작업. 서명·조건부 공증·아티팩트 업로드가 이어집니다.
Windows 검증windows-2025, Node.js 24, Go 1.26.1.github/workflows/windows-observation.yml. 테스트·빌드와 WPF 기반 실제 입력·관찰 검증 절차를 정의합니다.
프로빙 CLIGo 1.26.0, MCP Go SDK v1.4.1scripts/computer-use-cli/go.mod. Windows·Linux 제품 런타임과 별개의 조사용 CLI입니다.
검증 스크립트scripts/ci.sh문서·저장소 위생·액션 SHA 고정, 셸·JS 구문, Node·Python 및 조건부 Go 테스트를 연결합니다.

Go SDK v1.4.1을 macOS MCP 서버의 의존성으로 오해하면 안 됩니다. macOS의 StdioMCPServer는 Foundation으로 JSON을 직접 처리하고, 해당 SDK는 별도 프로빙 CLI에 쓰입니다. Windows·Linux의 제품 go.mod에는 외부 require가 없습니다.

제품 빌드의 중심은 Swift Package Manager, Go, npm 패키징과 운영체제별 스크립트입니다. 별도 웹 프론트 빌드나 컨테이너를 필수 실행 경로로 가정할 근거는 없습니다. CI 파일의 존재는 설정된 절차의 증거이며, 특정 실행이 성공했다는 증거는 아닙니다.

4아키텍처 심화 분석

요청 하나가 운영체제까지 내려가는 경로와 네 가지 설계 패턴

4-1. 전체 시스템 구조

아래 그림에서 AI의 판단은 클라이언트 쪽에 있습니다. 로컬 실행 엔진은 관찰 결과를 돌려주고, 지정된 액션을 처리합니다. JavaScript 어댑터는 선택 가능한 상위 계층이며, 일반 MCP 클라이언트는 네이티브 서버로 바로 연결할 수 있습니다.

[AI 에이전트 / MCP 클라이언트] | JSON-RPC 요청 |----------------------------------------+ v | [선택: Node.js REPL 어댑터] | js / js_reset | WorkerJavaScriptSession + createCuaApi() | app.query() / app.click() / app.getAXState() | | JsonLinePeer: 표준 입력·출력 | v v [운영체제별 native MCP 서버] macOS: StdioMCPServer.handle(line:) | ComputerUseToolDispatcher.callTool() v ComputerUseService |-- AppDiscovery: 앱·프로세스 찾기 |-- SnapshotBuilder: AX 트리 + 이미지 |-- TargetedElementRegistry: query 번호 관리 |-- InputSimulation: 입력 이벤트 |-- SoftwareCursorOverlay: 시각 피드백 +-- AgentDisplay: 별도 디스플레이로 창 배치 | v [macOS SDK / 일부 비공개 SPI] ---> [대상 앱] [다른 플랫폼의 구현 경계] Windows Go 서버 ---> PowerShell ---> UIA / Win32 Linux Go 서버 ---> Python ---> AT-SPI / GDK [macOS 권한 호스트 경로] CLI ---> MacOSAppAgentProxy ---> 숨은 .app 호스트 | 같은 서비스 계층 +---> 운영체제 권한·UI

OpenComputerUseMain.run()은 명령을 파싱한 뒤 프록시 사용 여부를 먼저 판단합니다. 직접 mcp를 처리하는 분기에서는 ComputerUseService와 StdioMCPServer를 만들고, 커서 UI가 활성화되어 있으면 MCPAppRuntime.run(server:)으로 앱 이벤트 루프를 함께 유지합니다.

이것은 네트워크로 연결된 마이크로서비스 그림이 아닙니다. 라이브러리 내부 호출, 자식 프로세스의 파이프, 로컬 앱 호스트 통신을 한눈에 표시한 것입니다. 화살표마다 같은 종류의 통신이 일어난다고 생각하면 안 됩니다.

4-2. 패턴 ① 전송·분배·업무 로직을 나눈 계층 구조

packages/OpenComputerUseKit/Sources/OpenComputerUseKit/MCPServer.swift의 run()은 줄 단위 입력을 읽습니다. handle(line:)이 initialize, tools/list, tools/call 등을 구분하고, 도구 호출을 ComputerUseToolDispatcher.callTool(name:arguments:)에 넘깁니다.

// MCPServer.swift에서 도구 호출 분기만 발췌
case "tools/call":
    let name = params["name"] as? String ?? ""
    let arguments = params["arguments"] as? [String: Any] ?? [:]
    let result = try dispatcher.callTool(name: name, arguments: arguments)
    return try encodeJSONRPCResult(
        id: id,
        result: result.asDictionary
    )

분배기는 필수 문자열, 요소 번호, 옵션을 해석합니다. 예를 들어 strictObservationBool()은 include_ax를 문자열이나 숫자에서 느슨하게 변환하지 않고 진짜 JSON 불리언인지 확인합니다. 서비스는 이 값들을 받아 앱 관찰과 조작을 수행합니다.

비유

식당에서 전화 주문을 받는 직원이 MCP 서버, 주문표를 담당 부서로 나누는 직원이 분배기, 실제 요리사가 서비스입니다. 전화기 교체가 요리법 변경으로 이어지지 않도록 책임을 나눈 것입니다.

실패도 두 층으로 구분해 읽어야 합니다. 알 수 없는 메서드는 JSON-RPC 오류 -32601로 응답하지만, 도구 실행 실패는 content와 isError가 담긴 결과로 돌아올 수 있습니다. 응답이 JSON으로 정상 도착했다는 사실만으로 클릭 성공을 판단해서는 안 됩니다.

4-3. 패턴 ② 클릭 전략 선택과 조건부 대체 경로

ComputerUseService.swift의 ClickMethod 열거형은 auto, accessibility, app_post, sky_click, global을 구분합니다. 인터페이스를 여러 클래스로 쪼갠 형태는 아니지만, 호출자가 선택한 전략에 따라 실행 경로가 달라지는 설계입니다.

click(app, element_index, click_method="auto") | +-- 입력 인자·현재 스냅샷 확인 +-- 요소 번호 -> 현재 기록 -> 클릭 위치 +-- performAXClickSequence() 시도 | | | +-- 처리됨 -> 결과 경로로 | +-- 처리 안 됨 -> performNonAXClickFallback() | | | +-- 기본: 대상 PID 입력 | +-- 전역 입력 허용 시: 실제 포인터 경로 +-- 시각 피드백 -> 설정에 따른 상태 다시 읽기

요소를 지정한 auto 경로는 접근성 액션을 먼저 시도합니다. 처리되지 않으면 다른 입력 경로를 사용합니다. validateClickMethod()는 accessibility 방식에 요소 번호가 필요함을 검사하고, global에는 환경변수로 명시적 허용을 요구합니다.

여기서 중요한 조건은 OPEN_COMPUTER_USE_ALLOW_GLOBAL_POINTER_FALLBACKS=1입니다. 기본 비접근성 대체 경로는 InputSimulation.clickTargeted(..., pid:)를 시도하지만, 전역 입력을 허용하면 prepareAppForGlobalPointerInput()과 clickGlobally() 경로를 사용할 수 있습니다.

자동화의 대체 경로는 성공률을 높이지만, 사용자에게 미치는 영향까지 바꿀 수 있으므로 조건과 부작용을 함께 읽어야 합니다.

또한 clickActionSnapshotRecoveryPolicy()는 sky_click에 읽기 전용 정책을 주고, 다른 방식에는 활성화를 허용하는 정책을 줍니다. “실제 포인터를 기본으로 움직이지 않는다”와 “어떤 경우에도 포커스를 바꾸지 않는다”는 다른 약속입니다.

4-4. 패턴 ③ 수명이 제한된 핸들과 유한한 탐색

packages/OpenComputerUseKit/Sources/OpenComputerUseKit/TargetedQuery.swift의 TargetedElementRegistry<Value>는 query 결과를 현재 네이티브 세션의 번호로 저장합니다. 첫 발급 번호는 1,000,001이고, 최대 5,000개를 보관하며, 기본 수명은 120초입니다.

// TargetedQuery.swift의 기본 설정을 발췌
static var indexBase: Int { 1_000_000 }

init(capacity: Int = 5000,
     lifetime: TimeInterval = 120,
     now: @escaping () -> Date = Date.init) {
    self.capacity = max(1, capacity)
    self.lifetime = lifetime
    self.now = now
}

이 번호는 영구 ID가 아닙니다. resolve()는 만료 여부와 앱 신원을 검사합니다. 신원에는 PID뿐 아니라 bundle identifier와 실행 시각도 들어갑니다. 프로세스가 재시작되어 같은 PID를 받더라도 이전 요소를 그대로 신뢰하지 않도록 하는 장치입니다.

ComputerUseService.snapshotForAction()은 조회 번호를 해석한 뒤, SnapshotBuilder.currentGeometry(of:in:criteria:)로 창 소속·역할·식별자·검색 조건·현재 프레임을 다시 확인합니다. 현재 요소를 다시 검증하는 단계에서 실패하면 해당 조회 번호를 삭제하고 오류를 반환합니다. 이 경로는 오래된 좌표로 조작을 계속하지 않습니다.

탐색 자체도 무한정 이어지지 않습니다. boundedTargetedWalk()는 큐와 방문 집합을 쓰는 너비 우선 탐색이며, 노드 수·결과 수·시간 제한·접근성 오류로 중단합니다. targetedSearch()는 2초의 협력적 마감 시간을 둡니다. 진행 중인 운영체제 호출을 정확히 2초에 강제 중단하는 보장은 아닙니다.

결과 필드질문독자가 해석할 내용
matches무엇을 찾았나?현재까지 발견한 일치 요소입니다.
truncated끝까지 살펴봤나?true이면 검색이 불완전합니다.
stop_reason왜 멈췄나?limit, max_nodes, timeout, ax_error 등을 구별합니다.
visited_nodes얼마나 조사했나?빈 결과와 작은 탐색 예산을 구분할 단서입니다.

matches: []인데 truncated: true라면 “그 버튼이 없다”고 결론 내릴 수 없습니다. 찾지 못한 이유를 결과에 실어 보내는 설계는 검색 API와 데이터 수집기에도 유용합니다.

4-5. 패턴 ④ 정책과 부작용을 나눈 상태 머신

packages/OpenComputerUseKit/Sources/OpenComputerUseKit/LockedUseStateMachine.swift는 macOS 잠금 상태 작업 실험의 정책을 값 타입 struct로 표현합니다. Phase에는 idle, preparing, authorizing, unlocking, active, relocking, awaitingManualUnlock가 있습니다.

begin(), guardsPrepared(), consumePermit(), tick()은 전제 조건을 검사하고 상태를 바꾸거나 실행할 효과를 반환합니다. Effect의 prepareGuards·requestUnlock·requestRelock 같은 값은 실제 시스템 동작과 정책 판단을 구분합니다.

비유

교통 신호 제어기가 “빨간불로 바꿔야 한다”는 판단을 내리는 것과, 전선을 통해 실제 신호등을 켜는 일을 나누는 방식입니다. 판단 부분을 분리하면 실제 도로를 통제하지 않고도 잘못된 전환과 시간 초과를 검토할 수 있습니다.

이 상태 머신의 시간 기준은 호출자가 전달하는 단조 증가 시간입니다. 허가 수명 5초, heartbeat 제한 3초, 유휴 제한 30초, 최대 임대 300초가 선언되어 있습니다. 이는 Locked Use 실험의 정책값이며 일반 MCP 호출의 공통 타임아웃이 아닙니다. docs/ARCHITECTURE.md는 전체 장애 행렬의 실증 검증이 아직 필요하다고 명시합니다.

4-6. 좌표 변환: 사진의 픽셀과 창의 포인트는 다르다

screenshotPixelScale()은 반환된 이미지의 픽셀 크기를 창 크기로 나누고, screenshotPixelToWindowPoint()는 클릭 픽셀을 그 비율로 나눕니다. 이미지 축소 설정이 있으므로 배율을 무조건 2로 고정하면 안 됩니다.

# ComputerUseService.swift의 좌표 계산을 숫자로 풀어쓴 예시
창 크기        = 1000 × 600 포인트
반환 이미지    = 1280 × 768 픽셀
x 배율, y 배율 = 1.28, 1.28
이미지 클릭점  = (640, 384)
창 내부 좌표   = (640 / 1.28, 384 / 1.28) = (500, 300)
# 이후 창의 전역 위치를 반영한다.
# AppKit 표시 좌표는 화면별 원점과 y축 방향도 구분한다.

screenStatePointToAppKitGlobalPoint()는 화면별 프레임을 사용해 커서 표시 좌표를 바꿉니다. “좌표 두 개를 넘긴다”는 API 뒤에도 이미지 크기, 창 위치, 화면 배치라는 서로 다른 기준이 있다는 점이 핵심입니다.

4-7. 세션 종료와 상태 읽기의 비용도 아키텍처다

일반 네이티브 경로는 기본적으로 액션 후 상태를 다시 읽습니다. 반면 REPL 어댑터는 OPEN_COMPUTER_USE_ACTION_READ_BACK=0을 사용해 액션의 자동 관찰을 줄이고, 코드가 필요한 지점에서 getAXState()를 호출하도록 합니다. 같은 클릭이라도 호출 계층에 따라 결과 사용법이 달라집니다.

WorkerJavaScriptSession.run()은 평가를 큐에 직렬로 넣습니다. 제한 시간을 넘으면 워커를 종료하고 새 워커를 시작하며 네이티브 세션도 끝냅니다. 이는 무한 반복문이 평가 워커를 붙잡는 문제에 대응하는 구조이지, 이미 대상 앱에 전달한 액션을 되돌리는 트랜잭션은 아닙니다.

StdioMCPServer.endSession()은 조회 인덱스를 비우고 커서·백그라운드 창 상태를 정리합니다. 각 ocu call 프로세스 사이에 요소 번호가 공유된다고 가정하면 안 됩니다. 여러 단계를 연결하려면 같은 네이티브 세션이 필요합니다.

5디렉토리 구조 해부

초보자는 문서 전체보다 도구 호출 한 갈래를 먼저 읽는다
open-computer-use/ ├── Package.swift / Package.resolved Swift 타깃과 의존성 ├── package.json 저장소 패키징 명령 ├── apps/ │ ├── OpenComputerUse/ macOS CLI·권한 창·앱 호스트 │ ├── OpenComputerUseFixture/ 제어 가능한 GUI 시험 앱 │ ├── OpenComputerUseSmokeSuite/ MCP 종단 간 검증 프로그램 │ ├── OpenComputerUseWindows/ Go + runtime.ps1 │ └── OpenComputerUseLinux/ Go + runtime.py ├── packages/ │ ├── OpenComputerUseKit/ │ │ ├── Sources/OpenComputerUseKit/ │ │ └── Tests/OpenComputerUseKitTests/ │ ├── OpenComputerUseVirtualDisplayShim/ Objective-C 연결 │ └── LockedUseNative/ 네이티브 신원 확인 ├── experiments/ │ ├── CursorMotion/ 커서 움직임 실험 앱 │ ├── StandaloneCursor/ 독립 커서 실험·테스트 │ └── LockedUse/ 잠금·허가·보호 실험 ├── scripts/ │ ├── node-repl/ JavaScript 어댑터·CLI │ ├── npm/ 패키지 생성·게시 도구 │ ├── computer-use-cli/ 별도 Go 프로빙 CLI │ └── tests/ 설치·런처·플랫폼 검증 ├── plugins/open-computer-use/ 플러그인 메타데이터·실행 연결 ├── skills/open-computer-use/ 에이전트 사용 지침 ├── docs/ 설계·릴리스·조사 기록 └── .github/workflows/ 릴리스·Windows 검증

apps/는 “어떻게 시작하고 어떤 프로세스로 실행하는가”, packages/는 “실제로 무엇을 하는가”에 가깝습니다. experiments/는 이름만 보고 전부 제품 경로와 분리되어 있다고 단정하면 안 됩니다. 실제로 Package.swift는 그 안의 Locked Use 실행 파일도 타깃으로 선언합니다.

5-1. 첫 독해에 추천하는 파일 순서

  1. Package.swift: 제품·라이브러리·실험·테스트 타깃의 연결부터 그립니다.
  2. apps/OpenComputerUse/Sources/OpenComputerUse/OpenComputerUseMain.swift: 명령과 실행 경로를 찾습니다.
  3. packages/OpenComputerUseKit/Sources/OpenComputerUseKit/ToolDefinitions.swift: 외부에 약속한 입력 스키마를 읽습니다.
  4. 같은 디렉토리의 MCPServer.swift → ComputerUseToolDispatcher.swift → ComputerUseService.swift: 도구 하나만 추적합니다.
  5. TargetedQuery.swift와 대응 테스트: 시스템 API와 독립적으로 이해할 수 있는 작은 알고리즘을 읽습니다.

AccessibilitySnapshot.swift는 2,616줄, ComputerUseService.swift는 2,346줄입니다. 처음부터 끝까지 읽기보다 query나 click 한 갈래를 검색해 따라가면 책임의 경계를 파악하기 쉽습니다.

5-2. 언어별 코드 규모

커밋 43eb4b5의 apps/, packages/, experiments/, scripts/에서 아래 확장자의 파일을 세었습니다. 빈 줄·주석·테스트를 포함한 줄바꿈 문자 수이며, 문서·외부 참고 번들·이미지·빌드 산출물은 집계 범위 밖입니다.

언어파일 수대략적인 줄 수
Swift15135,921
Go116,592
Python185,569
JavaScript194,726
Shell353,185
PowerShell82,163
Objective-C2379
C5362
공용 헤더253
합계25158,950

이 수치는 GitHub의 언어 비율과 다른 기준입니다. 예를 들어 Go 프로빙 CLI와 테스트용 Python 스크립트도 포함됩니다. “주 언어 Swift”라는 분류 아래 운영체제 연결과 배포를 위한 여러 언어가 있다는 점을 보여주는 지도입니다.

6학습 포인트 (기술별)

문법을 외우기보다 이 코드가 해결하는 제약을 함께 배우기

6-1. Swift: 값 타입과 참조 타입의 선택

SnapshotObservationOptions는 불리언 두 개를 가진 struct이고, ComputerUseService는 앱별 스냅샷을 유지하는 final class입니다. 작은 설정값과 공유 상태를 가진 서비스가 서로 다른 타입으로 표현되는 이유를 비교해 보세요.

// SnapshotObservationOptions.swift의 검증 메서드
public func validate() throws {
    guard includeAX || includeScreenshot else {
        throw ComputerUseError.invalidArguments(
            "At least one of include_ax or include_screenshot must be true"
        )
    }
}

오류 문구는 “접근성 정보와 스크린샷 중 적어도 하나를 포함해야 한다”는 뜻입니다. 두 옵션을 모두 끄는 조합을 입력 경계에서 거부합니다. 실습 아이디어: 가능한 네 조합을 적고 어떤 조합이 왜 실패해야 하는지 설명해 보세요.

관찰 조합수집하는 것다음 액션의 조건
둘 다 켬접근성 정보와 스크린샷을 요청합니다.실제로 반환된 요소와 이미지의 사용 가능 여부를 확인합니다.
AX만 켬캡처와 이미지 인코딩을 생략합니다.이 관찰을 바탕으로 스크린샷 좌표 액션을 수행할 수는 없습니다.
이미지만 켬접근성 트리·포커스·선택 정보 수집을 생략합니다.이전 요소 번호는 무효화됩니다. 요소 액션 전 AX를 다시 읽습니다.
둘 다 끔요청을 거부합니다.적어도 하나를 켠 유효한 관찰 요청이 필요합니다.

이는 응답에서 필드만 숨기는 옵션이 아닙니다. rememberSnapshot()은 AX를 생략한 앱의 이전 스냅샷 별칭과 조회 번호를 정리합니다. 비용을 줄이는 설정이 후속 액션의 유효성에도 영향을 준다는 점을 함께 배울 수 있습니다.

6-2. Swift와 AppKit: 이벤트 루프와 스레드 경계

MCPAppRuntime.swift는 NSApplication.run()으로 UI 이벤트 루프를 유지하면서, processStandardIO()를 별도 스레드에서 처리합니다. 입력 스트림을 기다리는 일이 UI 이벤트 처리를 막지 않게 하는 구조입니다.

PermissionOnboardingApp와 주 진입점에는 @MainActor가 보이지만, 핵심 전체가 Swift actor만으로 구성된 것은 아닙니다. 기존 Thread·DispatchQueue·잠금도 함께 쓰입니다. 실습 아이디어: 표준 입력 읽기, 앱 종료, 커서 표시 각각이 어느 실행 경계에 놓이는지 표시해 보세요.

용어
이벤트 루프
마우스 움직임, 창 다시 그리기, 타이머 같은 사건을 계속 받아 처리하는 반복 구조입니다. 그 루프를 오래 붙잡는 작업이 있으면 창이 멈춘 것처럼 보일 수 있습니다. async라는 단어가 보인다는 이유만으로 모든 작업이 별도 스레드에서 실행된다고 해석하면 안 됩니다.

6-3. MCP와 JSON-RPC: 성공을 여러 층으로 나누기

ToolDefinitions.swift는 도구의 이름·설명·스키마를 만들고, ToolResult.swift는 텍스트와 이미지 블록을 결과로 묶습니다. 이미지 바이트는 base64 문자열로 전달됩니다.

실습 아이디어: 동일한 요청에 대해 ① 알 수 없는 메서드, ② 알 수 없는 도구, ③ 유효한 도구지만 잘못된 앱을 지정한 경우를 각각 어떤 경로가 처리할지 그려보세요. 통신 성공, 도구 성공, UI에서 의도한 변화는 구별해서 설명해야 합니다.

버전 선언도 확인할 가치가 있습니다. JS JsonLinePeer.initialize()는 2025-06-18을 요청하고, macOS 서버는 2025-03-26을 응답합니다. 요청 문자열이 같지 않다는 사실과 실제 호환성 검증은 별개의 문제입니다.

6-4. 알고리즘과 테스트: 데스크톱 없이도 탐색을 이해하기

boundedTargetedWalk()는 노드 조사와 자식 조회를 클로저로 받습니다. 진짜 창 대신 정수로 만든 가짜 그래프를 넣을 수 있습니다. 화면 자동화 코드 안에서도 순수한 탐색 로직을 뽑아낼 수 있다는 뜻입니다.

packages/OpenComputerUseKit/Tests/OpenComputerUseKitTests/TargetedQuerySafetyTests.swift에는 순환 그래프 중복 제거, 넓은 트리의 예산 제한, 만료, 다른 앱의 번호 거부를 검증하는 XCTest 코드가 있습니다. 실습 아이디어: testTraversalDeduplicatesCyclesAndStopsAtResultLimit()을 읽고 큐·방문 집합·결과 배열을 손으로 갱신해 보세요.

6-5. 이미지 처리: 품질·비용·정확도를 함께 보기

ImageCaptureConfig.swift의 기본값은 PNG, JPEG 품질 0.8, ScreenCaptureKit 캡처 제한 5초, 최대 긴 변 1,280픽셀, 초과 시 축소, 총 픽셀 수 64 미만 이미지 생략입니다. 64픽셀은 한 변의 길이가 아니라 면적입니다. 테스트는 7×9의 생략과 8×8의 허용을 구분합니다.

설정 우선순위는 환경변수 → JSON 파일 → 기본값입니다. 기본 파일 위치는 ~/.config/ocu/config.json이며 XDG_CONFIG_HOME이나 OPEN_COMPUTER_USE_CONFIG_FILE로 바뀔 수 있습니다. 실습 아이디어: 파일의 긴 변 제한이 640이고 유효한 환경변수가 800일 때의 결과를 예측하고 ImageCaptureConfigTests.swift와 대조해 보세요.

캡처 경로도 README의 짧은 설명보다 복잡합니다. WindowCapture.captureImage()는 허용되는 경우 SkyLight 하드웨어 캡처를 먼저 시도하고, 실패하거나 해당 경로를 사용할 수 없으면 ScreenCaptureKit으로 내려갑니다. SDK 이름 하나만으로 전체 경로를 설명하지 않는 연습이 됩니다.

6-6. Go·Python·PowerShell: API는 공유하고 구현은 바꾸기

두 Go 런타임은 //go:embed로 각 플랫폼의 스크립트를 포함합니다. Linux는 gi.repository.Atspi, Windows는 UIAutomationClient·UIAutomationTypes와 Win32를 사용합니다. 실행 파일에 스크립트가 들어 있어도 Python·PowerShell 등 실행 환경이 불필요해지는 것은 아닙니다.

실습 아이디어: 세 플랫폼의 get_app_state 옵션과 click_method를 표로 비교하세요. Linux의 app_post·sky_click 거부처럼 이름만 공유하는 옵션을 찾아야 합니다. 교차 플랫폼 설계의 목표는 호출 모양의 공통화이지 운영체제 기능의 완전한 동일화가 아닙니다.

6-7. Node.js: 상태 유지와 강제 종료의 경계

WorkerJavaScriptSession은 별도 워커를 사용하고, JsonLinePeer는 요청 ID와 대기 중인 응답을 관리합니다. AsyncLocalStorage는 지연된 콜백의 출력이 어느 평가에 속하는지 추적하는 데 쓰입니다.

// 준비된 macOS REPL 세션에서 수행하는 조회 예시
// TextEdit가 이미 실행 중이어야 한다. 아래 코드는 클릭하지 않는다.
var editor = await cua.getApp("TextEdit", { initialState: false });
var found = await editor.query({ role: "AXTextArea", limit: 10 });
nodeRepl.write(found);

// 실제 역할 이름은 앱이 노출하는 AX 정보에 따라 확인한다.
// found.matches뿐 아니라 truncated와 stop_reason도 함께 읽는다.

initialState: false는 바인딩 시 전체 스냅샷을 건너뛰게 합니다. 이어지는 query()는 화면 전체를 전송하는 대신 조회 결과를 반환합니다. 이 API는 macOS 전용이며, 새 세션에서는 기존 변수를 다시 바인딩해야 합니다.

세션을 재시작하면 코드의 변수는 지울 수 있지만, 이미 앱에 전달한 클릭이나 입력까지 취소되지는 않습니다. 실습 아이디어: 시간 초과 직전에 클릭이 전달된 경우를 가정하고, 재시도 전 무엇을 관찰해야 중복 실행을 피할지 적어보세요.

6-8. 배포와 검증: 설정 파일도 읽을 수 있는 설계다

release.yml은 GitHub Actions를 전체 커밋 SHA로 고정하고, 서명 인증서가 없으면 ad-hoc 서명으로 대체하는 분기를 둡니다. 이때 권한 식별자가 설치별로 달라질 수 있다는 안내도 있습니다. 공증 역시 자격 정보와 서명 조건에 따라 수행됩니다.

실습 아이디어: “태그 생성 → 릴리스 문서 검증 → 패키징 → 조건부 공증 → 아티팩트 업로드”를 그린 뒤, 인증서나 공증 자격 정보가 없을 때 어느 단계가 달라지는지 표시하세요. 워크플로 정의와 배포물의 실제 보증을 구분하는 연습입니다.

7하드웨어 / 시스템 요구사항

코드를 읽는 환경과 실제 데스크톱을 조작하는 환경을 구분하기

소스를 읽고 JSON·탐색 알고리즘을 공부하는 데는 대상 운영체제의 GUI 권한이 필요하지 않습니다. 실제 실행을 준비할 때는 플랫폼마다 다음 조건을 확인해야 합니다. 아래 조건은 저장소 선언과 구현에 근거합니다.

환경확인할 조건소스 근거
macOSmacOS 14 이상. 배포 대상은 Apple Silicon arm64와 Intel x64입니다.Package.swift, build-open-computer-use-app.sh, npm 플랫폼 목록.
macOS 권한일반 관찰·조작에는 Accessibility와 Screen Recording을 확인합니다.Permissions.swift의 PermissionDiagnostics.current().
소스 빌드Swift tools 6.2 선언을 지원하는 도구 체인과 macOS SDK가 필요합니다.패키지 선언. 실제 설치용 바이너리 사용과 소스 빌드는 준비물이 다릅니다.
npm·JS 경로npm 런처는 Node.js 18 이상. REPL 어댑터와 해당 OS용 네이티브 런타임도 필요합니다.생성 패키지의 engines, README의 capabilities 설명.
WindowsWindows의 powershell.exe, UI Automation·Win32를 이용할 수 있는 데스크톱 환경이 필요합니다.main.go의 런타임 호출, runtime.ps1의 어셈블리 로드.
LinuxPython 3·PyGObject·AT-SPI와 활성 데스크톱 세션이 필요합니다. GDK는 선택적으로 로드합니다.runtime.py의 import와 require_desktop_session().
Linux 세션XDG_RUNTIME_DIR와 DBUS_SESSION_BUS_ADDRESS를 검사합니다.Go 런타임의 세션 환경 자동 탐색 후에도 변수가 없으면 활성 데스크톱 세션이 필요하다는 오류를 반환합니다.
CPU·RAM·GPU저장소의 실행 안내와 빌드 선언에는 정량적인 최소 CPU·RAM·VRAM 사양이 없습니다.이 프로젝트 자체는 모델 가중치를 로드하는 추론 서버가 아닙니다. 연결할 AI 클라이언트의 요구사항은 별도입니다.

이 프로젝트의 실행 조건은 GPU 용량보다 운영체제의 접근성 지원, 로그인 세션, 권한, 대상 앱의 상태에 더 직접적으로 연결됩니다.

7-1. 권한 진단이 알려주는 것과 알려주지 않는 것

macOS doctor --json은 platform, accessibilityTrusted, screenCaptureGranted, allGranted, missingPermissions를 반환합니다. 이 경로는 권한 안내 창을 열지 않습니다. 권한이 없더라도 종료 코드가 0이므로 JSON의 필드를 확인해야 합니다.

PermissionDiagnostics.current()는 시스템 API와 저장된 TCC 진단 정보를 함께 사용합니다. allGranted: true는 특정 앱의 특정 버튼이 성공적으로 눌린다는 증명은 아닙니다. 권한 변경 뒤 프로세스 재시작이 필요한 경우가 있다는 점도 README에 적혀 있습니다.

7-2. 일반 사용과 Locked Use 실험은 준비물이 다르다

docs/locked-use.en.md는 서명된 앱과 Locked Use 구성요소를 요구하고, Guardian에 Accessibility·Input Monitoring 권한을 설명합니다. 일반 권한 안내를 마쳤다고 Locked Use가 자동으로 켜지는 것은 아닙니다.

Linux의 AT-SPI 입력을 모든 Wayland 환경에서 통하는 백그라운드 조작으로 이해해서도 안 됩니다. Linux 서버 안내는 의미 기반 액션을 우선하며, 좌표·키 합성은 환경에 따라 성공을 보장하지 않는 대체 경로로 설명합니다. Windows·Linux는 docs/ARCHITECTURE.md에서 실험적 런타임으로 분류합니다.

8직접 해볼 수 있는 실습 과제

설치 없이 시작해, 계산·가짜 데이터·설계 산출물로 이해를 확인하기

아래 다섯 과제는 소스 읽기와 독립적인 작은 모형으로 수행할 수 있습니다. 실제 앱 조작과 시스템 잠금 설정은 요구하지 않습니다. 각 과제는 결과물을 남겨 이해 여부를 확인하도록 구성했습니다.

과제 1 · 입문 · 30분

도구 계약 지도 만들기 입문

목표: 외부 스키마와 내부 함수가 만나는 위치를 찾습니다.

  1. ToolDefinitions.swift에서 get_app_state와 click의 필수 인자를 적습니다.
  2. ComputerUseToolDispatcher.callTool()에서 생략된 옵션의 기본값을 찾습니다.
  3. ComputerUseService.click()에서 인자 조합에 따라 거부되는 경우를 두 개 찾습니다.

완료 기준: “도구 이름 / 필수 인자 / 기본값 / 서비스 함수 / 실패 조건” 표를 완성합니다. 예를 들어 accessibility 방식에는 요소 번호가 필요하며, 좌표만으로는 그 조건을 충족하지 못합니다.

과제 2 · 입문 · 40분

스크린샷 좌표 계산기 설계 입문

목표: 픽셀과 창 좌표를 구분합니다. screenshotPixelToWindowPoint()를 참고해 별도의 학습용 함수나 계산표를 만드세요.

# 운영체제 API를 부르지 않는 학습용 Python 함수
def to_window(point, image_size, window_size):
    scale_x = image_size[0] / window_size[0]
    scale_y = image_size[1] / window_size[1]
    return (point[0] / scale_x, point[1] / scale_y)

# 유효한 크기를 전제로 한 예시
# point=(640,384), image_size=(1280,768), window_size=(1000,600)
# 기대 결과: (500.0, 300.0)

완료 기준: 1배·2배·1.28배 이미지에서 같은 창 내부 위치가 나오는 사례를 각각 만듭니다. 0 크기나 누락값에 대해서는 위 학습용 함수와 실제 Swift 함수의 방어 처리가 어떻게 다른지 별도로 적으세요.

과제 3 · 중급 · 60분

끝나지 않는 트리를 유한하게 만들기 중급

목표: boundedTargetedWalk()의 예산·중복 제거·중단 이유를 손으로 재현합니다.

# 작은 가짜 그래프
0 -> [1, 2]
1 -> [0]
2 -> []

# 모든 노드가 일치하며, 자식 조회는 잘리지 않는다고 가정
maxNodes = 10
limit = 10
expired = false
  1. 큐, 큐의 읽기 위치, 방문 집합, 결과 배열을 한 단계씩 기록합니다.
  2. 순환 간선 1 → 0을 만나도 탐색이 끝나는 이유를 설명합니다.
  3. limit=1로 바꾸고 중단 이유와 결과 완전성이 어떻게 달라지는지 확인합니다.

완료 기준: 기본 결과가 [0, 1, 2]이며, limit=1에서는 [0]과 stop_reason=limit가 됨을 설명합니다. 결과가 하나라는 사실만으로 전체에 일치 요소가 하나라고 결론 내릴 수 없는 이유도 적으세요.

과제 4 · 중급 · 60~90분

요소 번호의 수명 실험표 만들기 중급

목표: TargetedElementRegistry의 시간과 앱 신원을 가짜 값으로 모델링합니다. TargetedQuerySafetyTests.swift의 만료·교체 테스트를 참고하세요.

  1. 용량 2개, 수명 10초, 가짜 시각 0초로 시작한다고 적습니다.
  2. 첫째·둘째·셋째 번호를 발급한 뒤 어떤 기록이 제거되는지 표시합니다.
  3. 시각을 정확히 10초로 옮겼을 때 남은 번호의 해석이 성공할지 판단합니다.
  4. 같은 PID이지만 실행 시각이 다른 앱을 넣는 경우와, 전체 비우기 뒤 번호를 발급하는 경우를 추가합니다.

완료 기준: 첫 기록의 축출, 경계 시각의 만료, 재시작 앱 거부, 비우기 뒤 증가하는 번호를 표로 설명합니다. 실제 기본 수명 120초와 테스트에서 바꾼 10초를 구별해야 합니다.

과제 5 · 고급 · 2~3시간

잠금을 조작하지 않는 상태 머신 모형 고급

목표: 정책과 시스템 부작용을 분리합니다. LockedUseStateMachine.swift의 begin(), guardsPrepared(), consumePermit(), tick()을 읽으세요.

  1. 상태·사건·전제 조건·반환 효과를 표로 옮깁니다.
  2. 허가 만료, 보호 장치 이상, 잘못된 소유자라는 세 실패 시나리오를 설계합니다.
  3. 독립 모형에서는 효과를 문자열로 기록하게 하고, 실제 잠금·권한·시스템 인증 호출은 넣지 않습니다.

완료 기준: 정상 경로와 실패 경로에서 어떤 효과가 반환되어야 하는지 설명하고, 모형에서 검증한 정책과 실제 운영체제에서 검증해야 할 동작을 나눠 적습니다.

좋은 실습 결과물은 “한 번 성공했다”는 화면보다, 어떤 입력과 상태에서 성공하거나 거부되어야 하는지 설명하는 표입니다.

9관련 기술 심화 학습 로드맵

6주 동안 인터페이스에서 운영체제 경계까지 내려가기

주당 3~5시간을 가정한 학습 순서입니다. 처음부터 모든 언어를 익히기보다, 익숙한 언어로 작은 모형을 만든 뒤 원래 Swift 구현과 비교하면 진도를 유지하기 쉽습니다.

주차배울 내용과 소스남길 결과물
1주차JSON, 표준 입출력, JSON-RPC 요청 ID. MCPServer.swift와 ToolDefinitions.swift를 읽습니다.도구 2개의 요청·응답·오류 경로 지도.
2주차Swift의 struct·class·enum·guard·throws. 분배기와 관찰 옵션을 읽습니다.입력 조합·기본값·거부 조건 표.
3주차트리, BFS, 방문 집합, 탐색 예산. TargetedQuery.swift와 관련 테스트를 읽습니다.순환·시간 초과·결과 제한을 다루는 가짜 그래프 모형.
4주차접근성 API, 창 좌표와 픽셀, 이미지 축소. AccessibilitySnapshot.swift의 필요한 함수만 추적합니다.좌표 계산표와 이미지 설정 우선순위 사례.
5주차Node.js 자식 프로세스·워커·Promise, 세션 수명. JsonLinePeer와 WorkerJavaScriptSession을 읽습니다.정상 응답·프로세스 종료·시간 초과의 순서도.
6주차Go 스크립트 내장, UIA·AT-SPI 차이, 상태 머신, 서명과 릴리스 흐름을 비교합니다.플랫폼 지원표와 정책·부작용 분리 설계안.

한 기능을 끝까지 추적하는 능력이 생기면, 익숙하지 않은 언어가 섞여 있어도 시스템의 경계부터 이해할 수 있습니다.

복습 기준
여섯 질문에 코드로 답할 수 있는가

누가 판단하는가? 어디서 입력을 검증하는가? 지금 상태는 누가 보관하는가? 실패를 어떻게 표현하는가? 시간 초과 뒤 무엇을 정리하는가? 다른 운영체제에서 어떤 약속이 달라지는가? 각 답에 파일·함수 하나를 연결할 수 있다면 핵심 구조를 이해한 것입니다.

10핵심 키워드 사전

처음 읽을 때 막히기 쉬운 단어를 이 저장소의 맥락으로 정리
용어쉬운 설명
Computer Use앱의 화면과 UI 요소를 읽고 클릭·입력으로 조작하는 방식입니다. 이 저장소는 그 실행 도구를 제공합니다.
MCPAI 클라이언트가 외부 도구의 목록을 확인하고 도구를 호출하는 데 쓰는 공통 규약입니다.
JSON-RPC메서드 이름·인자·요청 ID를 JSON에 담아 보내고, 같은 ID로 응답을 연결하는 호출 규칙입니다.
stdio표준 입력·표준 출력입니다. 이 프로젝트에서는 자식 프로세스와 줄 단위 메시지를 주고받는 통로가 됩니다.
접근성 트리창·버튼·입력칸의 관계를 계층으로 보여주는 구조입니다. 화면에 보이는 모든 것이 반드시 포함되지는 않습니다.
AXUIElementmacOS 접근성 API에서 앱이나 UI 요소를 가리키는 객체입니다. 역할·값을 읽거나 액션을 요청하는 데 사용합니다.
UI AutomationWindows의 UI 정보를 읽고 조작하는 접근성 체계입니다. 이 구현은 PowerShell에서 관련 .NET 어셈블리를 불러옵니다.
AT-SPILinux 데스크톱의 접근성 인터페이스입니다. 이 구현은 Python에서 요소 정보와 의미 기반 액션을 사용합니다.
스냅샷특정 시점에 읽은 앱 상태입니다. 앱이 바뀐 뒤에도 자동으로 항상 최신이 되는 실시간 객체는 아닙니다.
요소 인덱스현재 상태나 조회 결과의 요소를 가리키는 번호입니다. 영구 ID처럼 저장하고 나중에 재사용하면 안 됩니다.
핸들실제 객체를 직접 보내지 않고 가리키는 표식입니다. 조회 인덱스는 세션·수명·앱 신원의 제한을 받는 핸들입니다.
PID운영체제가 프로세스에 붙이는 번호입니다. 재사용될 수 있어 이 프로젝트의 조회 신원에는 실행 시각도 포함됩니다.
BFS가까운 단계부터 차례로 탐색하는 너비 우선 탐색입니다. 큐를 사용하며 방문 집합으로 순환을 막을 수 있습니다.
탐색 예산살펴볼 노드 수나 결과 수의 상한입니다. 시스템이 지나치게 오래 또는 많이 읽는 것을 제한합니다.
협력적 제한진행 중간에 시간을 확인해 멈추는 방식입니다. 이미 실행 중인 운영체제 호출을 즉시 강제 종료한다는 뜻은 아닙니다.
대체 경로첫 방법이 처리하지 못할 때 사용하는 다른 실행 방법입니다. 성공 조건뿐 아니라 부작용도 달라질 수 있습니다.
SPI여기서는 공개 API로 안정성이 약속되지 않은 내부 시스템 인터페이스를 가리킵니다. 운영체제 변경의 영향을 주의해서 봅니다.
가상 디스플레이물리 모니터 대신 운영체제에 추가하는 화면입니다. 여기서는 앱 창을 에이전트용 화면으로 옮기는 데 사용합니다.
REPL코드를 입력하고 결과를 읽는 반복 실행 환경입니다. 지속 세션은 이전에 만든 앱 변수 등을 유지할 수 있습니다.
WorkerNode.js의 별도 JavaScript 실행 스레드입니다. 여기서는 평가가 시간 초과되면 워커를 종료하고 다시 시작합니다.
상태 머신가능한 상태와 허용되는 전환을 명시한 모형입니다. 잠금 실험의 잘못된 순서와 허가 조건을 다룹니다.
임대와 heartbeat일정 시간만 유효한 사용 권한과 주기적인 생존 신호입니다. Locked Use 정책의 유지·중단 판단에 쓰입니다.
TCCmacOS의 개인정보 보호 권한 체계입니다. 접근성·화면 기록 허용 여부가 실제 실행 조건에 영향을 줍니다.
base64이미지 같은 바이트 데이터를 텍스트로 표현하는 인코딩입니다. 암호화와는 다르며, 전달 데이터 크기도 증가합니다.
서명·공증실행 파일의 발행 신원과 macOS 배포 검증에 관련된 절차입니다. 단순한 빌드 성공과는 다른 단계입니다.
고정 의존성항상 같은 버전이나 리비전을 선택하도록 정하는 것입니다. 이 프로젝트는 libwebp 의존성을 1.6.0으로 고정합니다.

11참고 링크

설명과 원본 코드를 오가며 확인할 수 있는 출처

11-1. 공식 저장소와 읽기 순서

11-2. 핵심 구현으로 바로 가기

11-3. 관련 기술의 공식 문서

공식 전송 규격에서 stdio는 줄바꿈으로 메시지를 구분하고, 로그는 표준 오류로 분리합니다. 따라서 예시 JSON을 보기 좋게 여러 줄로 표시한 것과 실제 전송 형식은 구분해야 합니다. 실제 요청은 한 줄로 직렬화합니다. MCP stdio 규격

현재 상태 (2026-10-23 확인)

항목상태기준
선정GitHub Trending Swift Weekly #42026-10-23 분석 기준.
스타 / 포크2,645 / 2452026-10-23 GitHub 기준.
주 언어SwiftGitHub 저장소 분류.
생성일2026-04-17GitHub 저장소 메타데이터.
최신 릴리스v1.1.2 · 2026-10-17GitHub 릴리스 기준. 플러그인 manifest도 1.1.2입니다.
최근 push2026-10-19GitHub 저장소 메타데이터.
최근 커밋43eb4b5 · 2026-10-19검증된 참고 번들 이전을 기록한 문서 커밋입니다.
코드 규모집계 대상 251파일 · 58,950줄앱·패키지·실험·스크립트, 해당 코드 확장자, 테스트·빈 줄·주석 포함.
Swift 규모151파일 · 35,921줄같은 집계 기준. 외부 참고 번들은 제외합니다.
네이티브 도구macOS 11개 / Windows·Linux 9개실제 도구 정의. JS 플러그인이 노출하는 2개 도구와 구별합니다.
라이선스MIT · Copyright 2026 Leo루트 LICENSE. 포함된 의존성과 참고 자료의 별도 고지도 함께 확인해야 합니다.
쓰기 전에 알아둘 한계
관찰 결과의 유효성과 플랫폼의 경계를 먼저 확인하세요

해설 기준: 커밋 43eb4b5의 소스·설정·테스트 정의를 기준으로 합니다. 실제 설치·GUI 조작의 성공 여부와 성능은 실행 환경별 검증이 필요합니다. 코드 규모는 명시한 범위의 줄 수입니다.

호환성과 부작용: Windows·Linux는 실험적 런타임이며 기능·옵션이 macOS와 완전히 같지 않습니다. 백그라운드 조작을 지향해도 앱 활성화가 허용되는 복구 경로가 있고, 전역 입력을 허용하면 실제 포인터·포커스에 영향을 줄 수 있습니다.

내부 API와 실험: SkyLightSPI.swift와 가상 디스플레이 shim은 비공개 인터페이스를 사용합니다. 운영체제 업데이트에 따른 호환성은 공개 API와 같은 수준으로 기대할 수 없습니다. Locked Use의 전체 장애 시나리오 검증도 진행 중입니다.

데이터 경계: 실행 엔진은 로컬이어도 반환한 접근성 텍스트와 이미지가 AI 클라이언트로 전달될 수 있습니다. 로컬 실행과 정보의 기기 외 전송 여부는 구별해야 합니다. 민감한 앱을 다룰 때는 연결한 클라이언트의 데이터 흐름까지 확인하세요.

상태와 안전: 요소 번호는 세션과 관찰 상태에 종속됩니다. 시간 초과는 이미 발생한 입력을 취소하지 않습니다. 서버 안내의 사용자 확인 지침과 런타임의 기술적 차단도 서로 다릅니다. 도구가 노출되어 있다는 사실만으로 모든 액션에 자동 승인 절차가 있다고 가정하지 마세요.