ch15. AI 도구 연동 -- Claude Session, Gemini with Raycast, Obsidian

AI 도구의 세션을 자동으로 관리하고, YouTube 영상을 Gemini로 분석하고, Cursor AI에 명령을 전달하는 매크로를 만든다. Keyboard Maestro와 AI 도구를 결합하여 반복 작업을 제거하는 방법을 배운다.

이런 불편함, 겪어보셨나요?

Claude를 터미널에서 사용한다. 세션이 길어지면 컨텍스트가 쌓여서 응답이 느려진다. 주기적으로 새 세션을 시작해야 하는데, 매번 수동으로 하기엔 번거롭다. 출근 전, 점심 후, 퇴근 전, 잠자기 전. 하루에 네 번 세션을 갱신하는 습관이 필요하다.

YouTube 영상을 보고 내용을 정리하는 작업도 반복적이다. 영상 링크를 복사하고, Gemini를 열고, 프롬프트를 입력하고, 결과를 기다린다. Raycast에서 링크를 전달하면 Gemini가 자동으로 분석을 시작하는 구조가 있다면 어떨까.

Cursor AI를 쓸 때도 마찬가지다. 채팅창에 질문을 입력한 뒤 제출 버튼을 누르는 동작. 단순하지만, 앱 전환과 키 입력을 매크로로 묶으면 워크플로우가 매끄러워진다.

이 챕터에서는 세 가지 AI 도구를 Keyboard Maestro로 자동화하는 매크로를 분석한다.

매크로 분석: Claude Session management

무엇을 하는 매크로인가

하루 네 번, 정해진 시각에 터미널을 열고 Claude CLI에 간단한 메시지를 보내서 새 세션을 시작한다.

트리거

트리거 타입 설명
Time 08:30 (매일) 출근 전 세션 시작
Time 13:30 (매일) 점심 후 세션 갱신
Time 18:30 (매일) 퇴근 전 세션 갱신
Time 23:01 (매일) 취침 전 세션 정리

네 개의 Time 트리거가 하나의 매크로에 등록되어 있다. 하나의 매크로에 여러 트리거를 붙이면, 어느 트리거가 발동하든 같은 액션이 실행된다. "같은 동작을 다른 시점에 반복"하는 패턴이다.

액션 흐름

flowchart TD A(["트리거: Time 08:30 / 13:30 / 18:30 / 23:01"]) --> B["SetActionDelay"] B --> C(["ActivateApplication: 터미널"]) C --> D{"PauseUntil: 터미널 활성화?"} D -->|조건 충족| E["InsertText: claude -p 'hi'"] E --> F(["SimulateKeystroke: Return"]) F --> G(["완료: 새 세션 시작"]) style A fill:#E3F2FD,stroke:#1976D2 style B fill:#F3E5F5,stroke:#7B1FA2 style C fill:#F3E5F5,stroke:#7B1FA2 style D fill:#FFF8E1,stroke:#FFA000 style E fill:#F3E5F5,stroke:#7B1FA2 style F fill:#F3E5F5,stroke:#7B1FA2 style G fill:#E3F2FD,stroke:#1976D2

그림 15-1. Claude Session management 매크로의 액션 흐름. 네 개의 Time 트리거가 동일한 액션 체인을 실행한다.

  1. SetActionDelay -- 액션 간 딜레이를 설정한다. 빠른 실행을 위해 최소값으로 둔다.
  2. ActivateApplication: 터미널 -- 터미널 앱을 활성화한다. 이미 열려 있으면 전면으로 가져온다.
  3. PauseUntil: 터미널 활성화 대기 -- 터미널이 실제로 포커스를 받을 때까지 기다린다. 앱 전환에는 시간이 걸릴 수 있으므로, 조건이 충족될 때까지 다음 액션을 보류한다.
  4. InsertText: claude -p 'hi' -- 터미널에 Claude CLI 명령어를 입력한다. -p 플래그는 프롬프트 모드를 의미한다. 간단한 인사 메시지로 새 세션을 시작한다.
  5. SimulateKeystroke: Return -- Enter 키를 눌러서 명령어를 실행한다.

핵심 기술 해설

다중 Time 트리거 패턴

Keyboard Maestro의 Time 트리거는 특정 시각에 매크로를 실행한다. ch12에서 다룬 Cron Job과 같은 원리다. 이 매크로의 특징은 하나의 매크로에 네 개의 Time 트리거를 등록했다는 점이다.

트리거를 네 개로 나누는 대신 하나의 매크로에 묶은 이유가 있다. 네 번의 실행이 모두 같은 액션을 수행하기 때문이다. 매크로를 네 개 만들면 관리 포인트가 네 배로 늘어난다. 액션을 수정할 때 네 곳을 모두 고쳐야 한다. 하나의 매크로에 트리거만 여러 개 붙이면, 액션은 한 곳에서만 관리하면 된다.

WhichDays 값이 127(이진수 1111111)로 설정되어 있다. 일요일부터 토요일까지 7비트를 모두 1로 채운 값이다. 주말 포함 매일 실행된다는 의미다.

PauseUntil 조건 대기

ActivateApplication은 앱에 활성화 요청을 보낼 뿐, 활성화 완료를 보장하지 않는다. 터미널이 배경에 있거나 다른 Space에 있으면 전면으로 오는 데 시간이 걸린다. PauseUntil은 "터미널이 최전면 앱인가?"라는 조건을 반복 확인한다. 조건이 참이 되면 다음 액션으로 넘어간다. 이 패턴은 앱 전환 후 텍스트를 입력하는 모든 매크로에서 권장된다.

InsertText vs TypeText

터미널에 명령어를 입력할 때 InsertText를 사용한다. TypeText는 한 글자씩 키 입력을 시뮬레이션하는 반면, InsertText는 클립보드를 통해 텍스트를 한 번에 붙여넣는다. 긴 문자열이나 특수 문자가 포함된 명령어에서는 InsertText가 더 안정적이다.

활용 팁

  • 세션 갱신 시각을 자신의 일과에 맞게 조정한다. 트리거의 TimeHour와 TimeMinutes 값만 바꾸면 된다.
  • claude -p 'hi' 대신 claude -p '오늘의 작업 목록을 보여줘'처럼 의미 있는 프롬프트로 바꿀 수 있다.
  • 주말에는 실행하지 않으려면 WhichDays를 62(이진수 0111110, 월~금)로 변경한다.
  • 비활성화 상태(IsActive: false)로 되어 있으므로, 사용하려면 매크로를 활성화해야 한다.

매크로 분석: Youtube - Gemini with Raycast

무엇을 하는 매크로인가

YouTube 영상 링크를 받아서 Gemini에게 분석을 요청하고, 결과를 기다리는 동안 원래 YouTube 탭으로 돌아오는 매크로다. 두 가지 버전이 존재한다. 하나는 Comet 브라우저를 사용하는 경량 버전이고, 다른 하나는 Chrome에서 Canvas 모드를 활용하는 확장 버전이다.

트리거

트리거 타입 설명
(없음) -- Raycast 또는 다른 매크로에서 호출. TriggerValue로 URL 전달

이 매크로에는 직접 트리거가 없다. Raycast의 Deeplink나 다른 매크로에서 TriggerValue를 통해 YouTube URL을 전달받는다. 서브매크로 호출 패턴과 유사하지만, 외부 앱에서 KM 매크로를 실행하는 구조다.

액션 흐름 (경량 버전 -- Comet 브라우저)

flowchart TD A(["트리거: Raycast Deeplink (TriggerValue=URL)"]) --> B["SetActionDelay"] B --> C(["ActivateApplication: Comet"]) C --> D(["SelectMenuItem: 탭 > Google Gemini"]) D --> E["SetVariable: url = %TriggerValue%"] E --> F["SearchReplace: 'TriggerValue=' 제거"] F --> G["JS: .ql-editor 입력창 포커스"] G --> H["InsertText: 분석 프롬프트 + URL"] H --> I(["SimulateKeystroke: Return"]) I --> J["AS: YouTube 탭으로 복귀"] J --> K(["완료"]) style A fill:#E3F2FD,stroke:#1976D2 style B fill:#F3E5F5,stroke:#7B1FA2 style C fill:#F3E5F5,stroke:#7B1FA2 style D fill:#F3E5F5,stroke:#7B1FA2 style E fill:#F3E5F5,stroke:#7B1FA2 style F fill:#F3E5F5,stroke:#7B1FA2 style G fill:#E8F5E9,stroke:#388E3C style H fill:#F3E5F5,stroke:#7B1FA2 style I fill:#F3E5F5,stroke:#7B1FA2 style J fill:#E8F5E9,stroke:#388E3C style K fill:#E3F2FD,stroke:#1976D2

그림 15-2. Youtube - Gemini with Raycast 경량 버전(Comet)의 액션 흐름. Raycast에서 전달받은 URL을 Gemini에 입력하고 YouTube 탭으로 복귀한다.

  1. SetActionDelay -- 딜레이 설정.
  2. ActivateApplication: Comet -- Comet 브라우저를 활성화한다. Gemini 전용 브라우저로 사용하는 구조다.
  3. SelectMenuItem: 탭 > Google Gemini -- 메뉴에서 Gemini 탭을 선택한다. 미리 고정해둔 탭으로 이동하는 방식이다.
  4. SetVariableToText: url = %TriggerValue% -- 전달받은 트리거 값을 변수에 저장한다.
  5. SearchReplace: "TriggerValue=" 제거 -- URL 앞에 붙는 접두어를 제거하여 순수한 URL만 남긴다.
  6. ExecuteJavaScript: 입력창 포커스 -- Gemini 페이지에서 입력창(.ql-editor)을 찾아 포커스를 설정한다.
  7. InsertText: 프롬프트 + URL -- YouTube 영상 분석을 요청하는 프롬프트와 URL을 입력한다.
  8. SimulateKeystroke: Return -- Enter 키로 프롬프트를 제출한다.
  9. ExecuteAppleScript: YouTube 탭 복귀 -- Gemini가 분석하는 동안 원래 YouTube 탭으로 돌아온다.

액션 흐름 (확장 버전 -- Chrome + Canvas)

확장 버전은 15개 액션으로 구성되며, 경량 버전보다 복잡한 워크플로우를 수행한다.

flowchart TD A(["트리거: Raycast Deeplink (TriggerValue=URL)"]) --> B["SetActionDelay"] B --> C["SafariControl: 현재 탭 URL 가져오기"] C --> D(["MouseMoveAndClick: Gemini 페이지 클릭"]) D --> E[/"0.3초 대기"/] E --> F(["PressButton: New chat"]) F --> G["SetVariable: url = %TriggerValue%"] G --> H["SearchReplace: 'TriggerValue=' 제거"] H --> I(["PressButton: Canvas"]) I --> J["JS: .ql-editor 입력창 포커스"] J --> K{"IfThenElse: 조건 분기"} K -->|Then| L["Shell: YouTube 영상 제목 가져오기"] L --> M["InsertText: 제목 포함 프롬프트"] K -->|Else| N["InsertText: 제목 없이 프롬프트"] M --> O(["SimulateKeystroke: Return"]) N --> O O --> P["AS: YouTube 탭으로 복귀"] P --> Q(["완료"]) style A fill:#E3F2FD,stroke:#1976D2 style B fill:#F3E5F5,stroke:#7B1FA2 style C fill:#E8F5E9,stroke:#388E3C style D fill:#F3E5F5,stroke:#7B1FA2 style E fill:#F3E5F5,stroke:#7B1FA2 style F fill:#F3E5F5,stroke:#7B1FA2 style G fill:#F3E5F5,stroke:#7B1FA2 style H fill:#F3E5F5,stroke:#7B1FA2 style I fill:#F3E5F5,stroke:#7B1FA2 style J fill:#E8F5E9,stroke:#388E3C style K fill:#FFF8E1,stroke:#FFA000 style L fill:#E8F5E9,stroke:#388E3C style M fill:#F3E5F5,stroke:#7B1FA2 style N fill:#F3E5F5,stroke:#7B1FA2 style O fill:#F3E5F5,stroke:#7B1FA2 style P fill:#E8F5E9,stroke:#388E3C style Q fill:#E3F2FD,stroke:#1976D2

그림 15-3. Youtube - Gemini with Raycast 확장 버전(Chrome + Canvas)의 액션 흐름. 조건 분기로 영상 제목 포함 여부를 결정한다.

  1. SafariControl -- 현재 탭 URL을 가져온다.
  2. MouseMoveAndClick -- Gemini 페이지의 특정 위치를 클릭한다.
  3. PressButton: New chat -- 새 채팅을 시작한다.
  4. 변수 설정 및 URL 정제 -- TriggerValue에서 URL을 추출한다.
  5. PressButton: Canvas -- Canvas 모드를 활성화한다. Gemini의 Canvas는 장문 출력에 적합한 모드다.
  6. ExecuteJavaScript: 입력창 포커스 -- .ql-editor에 포커스를 설정한다.
  7. IfThenElse: 조건 분기 -- 조건에 따라 다른 프롬프트를 입력한다. Then 경로에서는 셸 스크립트로 YouTube 영상 제목을 먼저 가져온 뒤 프롬프트에 포함시킨다. Else 경로에서는 제목 없이 프롬프트만 입력한다.
  8. SimulateKeystroke: Return -- 프롬프트를 제출한다.
  9. ExecuteAppleScript: YouTube 탭 복귀 -- 원래 탭으로 돌아온다.

핵심 기술 해설

TriggerValue를 통한 외부 데이터 수신

%TriggerValue%는 매크로가 실행될 때 전달받는 값이다. Raycast에서 KM 매크로를 호출할 때 URL을 파라미터로 넘긴다. 이때 값 앞에 TriggerValue=이라는 접두어가 붙는다. SearchReplace 액션으로 이 접두어를 빈 문자열로 치환하여 순수한 URL만 추출한다.

이 패턴은 외부 앱과 KM을 연동할 때 자주 사용된다. Alfred, Raycast, 셸 스크립트 등에서 KM 매크로를 호출하면서 데이터를 전달할 수 있다.

JavaScript로 웹 UI 조작하기

Gemini 입력창은 일반적인 <input>이나 <textarea>가 아니다. Quill.js 기반의 리치 텍스트 에디터(.ql-editor)를 사용한다. 일반적인 방법으로는 텍스트를 입력할 수 없다.

// 입력창(.ql-editor)에 포커스하기
const inputBox = document.querySelector('.ql-editor');

if (inputBox) {
  inputBox.focus();
} else {
  console.warn('입력창(.ql-editor)을 찾을 수 없습니다.');
}

ExecuteJavaScript로 먼저 입력창에 포커스를 설정한 뒤, InsertText로 텍스트를 붙여넣는다. 웹 앱의 커스텀 UI를 다룰 때는 이처럼 JavaScript와 KM 액션을 조합하는 접근이 필요하다.

AppleScript로 탭 전환하기

Gemini에 프롬프트를 제출한 뒤, 응답을 기다리는 동안 YouTube 탭으로 돌아온다. AppleScript로 브라우저의 모든 윈도우와 탭을 순회하면서 YouTube URL을 가진 탭을 찾는다.

tell application "Comet"
    activate
    set youtubeTabFound to false
    repeat with w in windows
        set tabList to tabs of w
        repeat with t from 1 to count of tabList
            set theTab to item t of tabList
            -- YouTube URL이 포함된 탭을 찾아서 활성화
        end repeat
    end repeat
end tell

이 패턴은 "작업 요청 후 원래 컨텍스트로 복귀"라는 워크플로우를 구현한다. 사용자가 기다리는 시간을 줄여주는 UX 설계다.

두 버전의 아키텍처 비교

경량 버전(9개 액션)은 Comet 브라우저의 고정 탭을 활용한다. 메뉴 선택으로 Gemini 탭에 접근하므로 탭을 찾는 과정이 단순하다. 확장 버전(15개 액션)은 Chrome에서 새 채팅을 시작하고 Canvas 모드를 활성화한다. 셸 스크립트로 영상 제목을 가져오는 추가 단계가 포함된다. 같은 목적의 매크로를 환경에 맞게 분기한 사례다.

활용 팁

  • Gemini 외에 ChatGPT, Claude 웹 등 다른 AI 서비스에도 같은 패턴을 적용할 수 있다. 입력창 셀렉터만 변경하면 된다.
  • 프롬프트 내용을 KM 변수로 분리하면, 프롬프트만 바꿔서 다른 분석을 요청할 수 있다.
  • Raycast Deeplink 설정 방법: Raycast에서 "Run Keyboard Maestro Macro" 확장을 설치하고, 매크로 이름을 지정한다.

매크로 분석: CursorChatSubmit

무엇을 하는 매크로인가

Cursor AI 에디터를 활성화하고, 채팅 입력을 제출하는 단축키(Command+Return)를 보내는 매크로다. 다른 매크로나 워크플로우에서 Cursor에 명령을 전달할 때 사용한다.

트리거

트리거 타입 설명
(없음) -- 다른 매크로에서 서브매크로로 호출

CursorChatSubmit 역시 직접 트리거가 없다. 복합 워크플로우의 부품으로 설계된 매크로다.

액션 흐름

flowchart TD A(["트리거: 서브매크로 호출"]) --> B(["ActivateApplication: Antigravity (Cursor)"]) B --> C["SetActionDelay: 0.02초"] C --> D(["SimulateKeystroke: Cmd+Return"]) D --> E(["완료: 채팅 제출"]) style A fill:#E3F2FD,stroke:#1976D2 style B fill:#F3E5F5,stroke:#7B1FA2 style C fill:#F3E5F5,stroke:#7B1FA2 style D fill:#F3E5F5,stroke:#7B1FA2 style E fill:#E3F2FD,stroke:#1976D2

그림 15-4. CursorChatSubmit 매크로의 액션 흐름. 세 개의 액션으로 구성된 간결한 서브매크로다.

  1. ActivateApplication: Antigravity -- Cursor AI(번들 ID: com.google.antigravity)를 활성화한다. Cursor의 내부 앱 이름이 Antigravity다.
  2. SetActionDelay: 0.02초 -- 키 입력 간 딜레이를 0.02초로 설정한다. 너무 빠르면 앱이 입력을 놓치고, 너무 느리면 체감 속도가 떨어진다.
  3. SimulateKeystroke: Command+Return -- 채팅 제출 단축키를 보낸다. Cursor에서 Command+Return은 채팅 메시지를 전송하는 단축키다.

핵심 기술 해설

앱 활성화와 딜레이 조정

세 개의 액션으로 구성된 간결한 매크로다. 하지만 이 단순함 안에 실전 노하우가 담겨 있다.

SetActionDelay를 0.02초로 설정한 이유가 있다. KM의 기본 딜레이는 키 입력에 비해 느릴 수 있다. AI 도구는 입력 이벤트 처리가 일반 앱과 다른 경우가 많다. Electron 기반 앱(Cursor, VS Code 등)은 키 이벤트를 비동기로 처리한다. 딜레이가 너무 짧으면 이벤트가 누락되고, 너무 길면 사용자가 지연을 체감한다. 0.02초는 이 균형점을 찾은 값이다.

서브매크로로서의 설계

이 매크로는 독립 실행보다 다른 매크로의 부품으로 사용하도록 설계되었다. 트리거가 없는 이유다. 예를 들어, 클립보드에 코드를 복사한 뒤 Cursor를 열고 "이 코드를 리팩토링해줘"라는 프롬프트와 함께 제출하는 복합 매크로를 만들 수 있다. CursorChatSubmit은 그 마지막 단계인 "제출"만 담당한다.

ch11에서 다룬 서브매크로 패턴과 같은 원리다. 하나의 동작을 하나의 매크로로 분리하면, 여러 워크플로우에서 재사용할 수 있다.

활용 팁

  • Cursor 외에 VS Code Copilot Chat, Windsurf 등 다른 AI 에디터에도 같은 패턴을 적용할 수 있다. 번들 ID와 제출 단축키만 변경하면 된다.
  • 앞에 InsertText 액션을 추가하면 프롬프트 입력까지 자동화할 수 있다.
  • 여러 AI 에디터용 Submit 매크로를 각각 만들어두면, 상위 매크로에서 조건 분기로 적절한 것을 호출할 수 있다.

세 매크로의 아키텍처 비교

세 매크로는 각각 다른 AI 도구를 자동화하지만, 공통 패턴이 있다.

앱 활성화 -> 입력 -> 실행 구조다. Claude Session은 터미널에 CLI 명령어를 입력한다. Gemini with Raycast는 브라우저에 프롬프트를 입력한다. CursorChatSubmit은 에디터에 제출 단축키를 보낸다.

AI 도구별 인터페이스가 다르기 때문에 접근 방법도 다르다. CLI 기반(Claude)은 InsertText로 충분하다. 웹 기반(Gemini)은 JavaScript로 DOM을 조작해야 한다. Electron 기반(Cursor)은 SimulateKeystroke로 단축키를 보낸다.

이 차이를 이해하면, 새로운 AI 도구가 나오더라도 적절한 자동화 전략을 선택할 수 있다.

직접 만들어보기

가장 실용적인 "Claude Session management" 매크로를 직접 만들어보자.

  1. KM 에디터에서 새 매크로 그룹을 만든다. 이름은 "AI Tools"로 설정한다.
  2. 새 매크로를 만들고 이름을 "Claude Session management"로 설정한다.
  3. 트리거를 추가한다: Time Trigger 를 선택한다.
    • Hour: 8, Minutes: 30으로 설정한다.
    • Days: Every day를 선택한다.
  4. 같은 방법으로 트리거를 세 개 더 추가한다.
    • 13:30, 18:30, 23:01로 각각 설정한다.
  5. 액션을 순서대로 추가한다:
    • Set Action Delay -- 원하는 딜레이 값을 설정한다.
    • Activate a Specific Application -- "터미널"을 선택한다.
    • Pause Until -- Conditions에서 "Front Application is 터미널"을 설정한다.
    • Insert Text by Pasting -- claude -p 'hi'를 입력한다.
    • Simulate Keystroke -- Return 키를 설정한다.
  1. 테스트: 매크로를 수동으로 실행(Try 버튼)한다. 터미널이 열리고 Claude CLI가 실행되는지 확인한다.

이 챕터에서 배운 것

  • 하나의 매크로에 여러 Time 트리거를 등록하여 같은 동작을 다른 시점에 반복하는 패턴
  • TriggerValue를 통해 외부 앱(Raycast)에서 KM 매크로로 데이터를 전달하는 방법
  • JavaScript로 웹 앱의 커스텀 UI(Quill.js 에디터)를 조작하는 기법
  • AI 도구의 인터페이스 유형(CLI, Web, Electron)에 따른 자동화 전략의 차이
  • 트리거 없는 매크로를 서브매크로로 설계하여 워크플로우의 부품으로 활용하는 방법

다음 챕터 예고

ch15는 이 책의 마지막 챕터다. 부록 A에서는 71개 매크로 전체 인덱스를 카탈로그 형태로 정리한다. 자신에게 필요한 매크로를 빠르게 찾아볼 수 있다.