GITHUB 레포 딥다이브 · 2026-08-03 · MICROSOFT/SKILL-RECORDER · 화면 녹화 한 번으로 AI 에이전트 스킬을 만든다

skill-recorder 딥다이브
— 시연 한 번을 AI 에이전트의 재사용 스킬로 바꾸는 녹화기

microsoft/skill-recorder당신이 화면에서 어떤 업무를 한 번 수행하는 장면을 녹화해, 그걸 AI 에이전트가 두고두고 다시 실행할 수 있는 스킬(SKILL.md) 또는 자동화(automation)로 바꿔 주는 Electron 데스크탑 앱이다. 핵심 슬로건은 "작업을 한 번만 해 보이면, AI가 반복할 수 있는 스킬이 된다(Record yourself doing a task once, then turn it into a skill your AI agent can repeat)".

결정적으로 이 앱은 마우스 좌표나 키 입력을 베끼지 않는다. 대신 "어떤 앱을 켰고, 어떤 URL에 갔고, 무엇을 복사했는가" 같은 의미 있는 OS 이벤트만 값싸게 잡아 GitHub Copilot에게 넘기고, Copilot이 "네가 하려던 것(의도) + 그 순서(단계)"를 재구성한다. 그리고 그 스킬은 UI 클릭을 재생하는 대신 에이전트의 진짜 도구(gh CLI, web_fetch 등)를 우선 쓰고, 예시 하나를 여러 건으로 일반화한다 — 폼 하나 제출을 녹화하면 폼 전부를 제출하는 스킬이 된다.

(저장소 microsoft/skill-recorder · 라이선스 MIT(Microsoft) · 버전 v0.3.1 · 형식 Electron + React 19 데스크탑 앱 · 언어 TypeScript(약 22,400줄) · AI 엔진 GitHub Copilot CLI(@github/copilot-sdk) · 온디바이스 음성인식 Whisper(transformers.js) · 파일 171개 · 최신 커밋 2026-07-30(Giorgio Ughini) · TrendShift Daily #13)
목차
  1. 한 줄 정체
  2. 왜 주목받는가 — "시연 기반 스킬 저작"이라는 각도
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 — 4단계 파이프라인과 결정론+LLM 분업
  5. 디렉토리 구조 해부
  6. 학습 포인트 — 기술별 배울 것
  7. 시스템 / 실행 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 로드맵 (주차별)
  10. 핵심 키워드 사전
  11. 참고 링크

1한 줄 정체

이 프로젝트가 정확히 무엇인지 한 문장으로

skill-recorder는 "당신이 화면에서 어떤 작업을 한 번 수행하면, 그 과정을 로컬에서 녹화해 GitHub Copilot이 '무엇을 하려 했는지(의도)'와 '어떤 순서로 했는지(단계)'로 재구성하고, 이를 AI 에이전트가 반복 실행할 수 있는 재사용 스킬(SKILL.md)이나 예약 자동화로 바꿔 주는 Electron 데스크탑 앱"이다. 한마디로 "시연 → 스킬"을 자동화하는 녹화기다. 스킬을 손으로 마크다운에 적는 대신, 실제로 한 번 해 보이면 된다.

한 장의 비유

"어깨너머로 한 번 보고 업무 매뉴얼을 써 주는 견습생"

영리한 견습생에게 일을 가르칠 때, 우리는 매뉴얼을 손으로 써 주지 않는다. 그냥 한 번 시연하면서 "지금 경비 정산서를 올리는 거야"라고 말해 준다. 견습생은 당신의 마우스가 정확히 몇 픽셀을 움직였는지 외우지 않는다 — "무엇을 하려는지(의도)"를 이해하고, 그걸 순서 있는 절차로 자기 노트에 정리한다. 그리고 다음부터는 굳이 화면을 똑같이 클릭하지 않고, 회계 시스템의 정식 기능(API)을 써서 더 빠르고 안정적으로 처리한다. 게다가 당신이 정산서 하나를 보여 줬을 뿐인데, 견습생은 정산서 전부를 처리할 줄 알게 된다.

skill-recorder가 정확히 이 견습생이다. ①녹화로 당신의 작업을 어깨너머로 지켜보되(키 입력이 아니라 앱·URL·클립보드 같은 의미를 본다), ②Copilot이 그걸 "의도 하나 + 순서 있는 단계들"로 재구성해 노트(SKILL.md)에 적고, ③실행할 땐 UI 클릭 재생 대신 gh·web_fetch 같은 네이티브 도구를 우선 쓰며, ④한 건의 예시를 N건으로 일반화한다. "따라 하기"가 아니라 "이해하고 재현하기"인 게 이 앱의 핵심이다.

용어
에이전트 스킬 (Agent Skill) · SKILL.md
SKILL.md는 YAML 머리말(name·description·선택적 allowed-tools)과 마크다운 지시 본문으로 이뤄진 파일이다. 다운스트림 AI 에이전트(Microsoft Scout, Cowork/M365 Copilot 등)가 이 파일을 자동으로 읽어, description이 지금 할 일과 맞으면 그 절차를 실행한다. 즉 프로그램이 아니라 "AI에게 주는 작업 매뉴얼"이다. skill-recorder가 최종적으로 뱉는 산출물이 바로 이 SKILL.md 한 벌이다.
용어
GitHub Copilot CLI · @github/copilot-sdk
이 앱의 AI 두뇌. skill-recorder는 @github/copilot-sdk로 Copilot CLI를 멀티턴 에이전트처럼 몰고 다닌다 — 세션을 만들고, 앱 안에서 정의한 커스텀 도구를 등록하고, 턴을 스트리밍한다. Copilot CLI는 앱에 함께 딸려 오며, 실제 "의도/단계 재구성"과 "스킬 생성" 추론을 담당한다. 그래서 GitHub 계정 + Copilot 접근 권한이 있어야 한다.

사용자가 녹화 버튼을 누르고 작업을 한 뒤 "Analyze → Create"를 누를 때, 내부에서 벌어지는 일을 압축하면 이렇다:

사용자 ⌘⇧R 로 녹화 시작 → 평소처럼 업무 수행 → 녹화 종료 │ (앱 전환·URL·클립보드·터미널 명령 = "의미 이벤트"를 로컬에 기록) ▼ ① 기록(Record) events.jsonl + 저프레임 화면 영상(+선택적 마이크 음성) │ ※ 전부 내 컴퓨터에만 저장. 이 단계에선 아무것도 밖으로 안 나감 ▼ ② 처리(Process) 이벤트를 "단계(step)"로 분절 → 프레임 추출·상관 → │ 결정론적 초안 description.md 생성 (Copilot 없이도 나옴) ▼ ③ 분석(Analyze) ← "Analyze" 누르는 순간에만 GitHub 클라우드로 전송 │ Copilot이 6개 샌드박스 도구로 타임라인·화면을 읽고 │ "의도 1개 + 순서 있는 단계들" = analysis.json 으로 재구성 │ (사용자가 검토·수정, 자연어로 피드백 가능) ▼ ④ 생성(Create) 승인된 분석 → 스킬 빌더/자동화 빌더(2단계 에이전트) → SKILL.md 를 ~/.copilot/skills 에 설치(또는 내보내기)

여기서 두 가지가 이 앱의 성격을 규정한다. 첫째, ①②는 전부 로컬이고 ③에서만 클라우드 전송이라는 프라이버시 경계다. 둘째, 잡는 신호가 픽셀·키스트로크가 아니라 "의미 이벤트"라는 점이다 — 이 둘이 뒤에서 설명할 "네이티브 도구 우선"과 "일반화"를 가능하게 하는 뿌리다.

2왜 주목받는가 — "시연 기반 스킬 저작"이라는 각도

Microsoft가 내놓은 v0.3짜리 신생 레포가 상위에 오른 이유

첫째, "AI에게 내 반복 업무를 어떻게 가르치나"라는 문제를 프롬프트가 아니라 시연으로 푼다. 요즘 다들 스킬(SKILL.md)이 뜨는 건 알지만, 정작 스킬을 손으로 마크다운에 적는 일은 번거롭고 감이 안 온다. skill-recorder는 그 진입장벽을 없앤다 — "한 번 해 보이면 스킬이 나온다"는 show, don't tell 프레이밍은 그 자체로 공유성이 크다.

둘째, Microsoft 조직 + 진짜 새로운 프리미티브라는 신뢰 조합이다. 스킬/SKILL.md 흐름(Claude·Copilot 스킬)에 올라타면서, 그동안 비어 있던 "스킬 저작(authoring)의 온램프"를 채웠다. 산출물은 Microsoft ScoutCowork(M365 Copilot)를 겨냥한다. TrendShift 데일리 2위 토픽이 마침 AI skills라는 점도 맞물렸다.

비유

매크로 녹화기와, 일 잘하는 조수의 차이다. 옛날 매크로/RPA 녹화기는 "3번째 줄, 좌표 (812, 344)를 클릭"을 그대로 재생한다 — 창 크기만 바뀌어도 깨지는 깨지기 쉬운 좌표 재생이다. skill-recorder는 좌표가 아니라 "이 사람이 지금 GitHub 이슈를 닫으려 하는구나"라는 의도를 읽고, 그걸 gh issue close 같은 정식 도구 호출로 바꾼다. 화면이 바뀌어도, 대상이 3건에서 300건으로 늘어도 안 깨진다. "손가락을 흉내 내는 것"과 "일을 이해하는 것"의 차이다.

셋째, 프라이버시 우선 설계가 클라우드 화면 녹화 도구들과의 확실한 차별점이다. 녹화·프레임 추출·음성 전사가 전부 내 컴퓨터에서 일어나고, "Analyze"를 누를 때만 업로드된다. 앱은 녹화 전마다 "비밀정보를 담지 말라"고 반복 경고한다.

넷째, v0.3답지 않은 엔지니어링 완성도가 별을 끈다. 순수·결정론적 코어(zod 스키마 계약 + 단위테스트), 세 갈래 평가(eval) 하네스(describer/automation-builder/skill-builder), 지각 해시 기반 프레임 중복 제거, 도구 샌드박싱 보안 태세, Windows ARM64까지 포함하는 크로스플랫폼, 그리고 번들 의존성 라이선스가 하나라도 미검토면 빌드를 실패시키는 컴플라이언스 게이트까지 — 마치 완제품 같은 밀도라 신뢰가 쌓인다.

이 레포의 진짜 강점
"따라 하기"가 아니라 "이해하고 일반화하기"

대부분의 화면 자동화는 녹화한 클릭을 그대로 재생한다. skill-recorder는 의미 이벤트 → 의도/단계 재구성 → 네이티브 도구 매핑 → N건 일반화로 전혀 다른 산출물을 만든다. 폼 하나 제출을 녹화하면 "모든 행의 폼을 제출하라"는 스킬이 나오고, UI 클릭 대신 gh·web_fetch·M365 API를 우선 쓴다. 심지어 "빌더가 gh 대신 브라우저를 골랐다"는 회귀를 잡는 전용 eval까지 둔다. RPA/UI 리플레이(UiPath, Playwright codegen)와 갈라지는 지점이 여기다.

오해 주의
"Analyze"는 클라우드로 데이터를 보낸다 · Copilot 접근이 필요하다

녹화 자체는 로컬이지만, Analyze를 누르는 순간 이벤트 타임라인(창·문서 제목, URL, 클립보드 미리보기), 추출된 화면 이미지, 내레이션 텍스트가 GitHub 클라우드로 전송돼 Copilot이 처리한다. 그래서 앱은 "비밀번호·토큰·API 키·기밀을 녹화·입력·붙여넣기·표시·복사·내레이션하지 말라"고 녹화 전마다 경고한다. 또 Analyze/Create에는 Copilot 접근 권한이 있는 GitHub 계정이 필수다. "설치하면 알아서 다 되는 로컬 전용 앱"으로 오해하면 안 된다.

3기술 스택 전체 지도

서버가 없는 데스크탑 앱 — Electron(백엔드 격) + React 19(프론트) + Copilot(추론) + 온디바이스 Whisper

skill-recorder는 서버 인프라가 없는 단일 데스크탑 앱이다. 그래서 스택은 "메인 프로세스(Electron·백엔드 역할)", "렌더러(React·프론트)", "AI 추론(Copilot 클라우드 + 온디바이스 Whisper)", "빌드·컴플라이언스 인프라"로 나뉜다. 의존성이 8개뿐인데 하나하나가 전략적으로 골라져 있다.

계층구성요소 / 버전역할
AI 엔진@github/copilot-sdk ^1.0.6이 앱의 심장. Copilot CLI를 멀티턴 에이전트로 구동 — 세션 생성, 커스텀 인프로세스 도구 등록, 턴 스트리밍. describer/builder의 추론을 담당
온디바이스 ASR@huggingface/transformers ^4.2.0transformers.js. Whisper 음성인식 모델을 내 컴퓨터에서 돌려 내레이션을 전사(99개 언어, GPU 불필요)
UI (프론트)react / react-dom ^19.2.5녹화 HUD, 라이브러리(세션 목록), 계획 편집 타일 등 렌더러 UI. React 19
데이터 계약zod ^4.3.6스키마 백본. 이벤트·번들·분석·스킬 계획 등 모든 데이터 계약을 zod 스키마로 정의하고 입출력 경계마다 검증
이미지 처리sharp ^0.34.5libvips 기반. 추출한 화면 프레임을 크롭·리사이즈해 모델에 보내기 전 다듬음. 지각 해시 계산에도 사용
FFI (Windows)koffi ^3.1.1네이티브 컴파일러 없이 Windows user32/dwmapi/kernel32를 직접 호출 → 전경 창 추적
창 추적(선택)get-windows ^9.3.0 optionalmacOS/Linux 전경 창 폴링(브라우저 URL은 Apple Events). optional이라 프리빌드가 없어도 Windows가 안 깨짐
압축archiver ^7.0.1내보낸 스킬 폴더·디버그 번들을 zip으로
용어
Electron · 메인 프로세스 vs 렌더러
Electron은 Chromium(웹 화면)과 Node.js(시스템 접근)를 한 데 묶어 웹 기술로 데스크탑 앱을 만드는 프레임워크다. 메인 프로세스(electron/)는 Node 권한으로 창 관리·전역 단축키·파일·OS 이벤트 수집 등 "백엔드" 일을 하고, 렌더러(src/)는 브라우저 창 안에서 React로 UI를 그린다. skill-recorder에서 무거운 로직(녹화·파이프라인·Copilot 호출)은 전부 메인에 있다.
용어
zod · 스키마 검증
zod는 TypeScript용 런타임 스키마 검증 라이브러리다. "이 객체는 이런 필드·타입이어야 한다"를 코드로 선언하면, 실제 데이터가 그 모양인지 실행 중에 검사해 준다. skill-recorder는 이벤트·번들·분석·스킬을 전부 zod로 정의해, LLM이 만든 산출물이 규격을 벗어나면 즉시 걸러내고 고칠 오류를 되돌려준다. "쓰레기 입력이 파이프라인 깊숙이 흘러들지 못하게" 막는 안전벨트다.

빌드·테스트·인프라 계층도 눈여겨볼 만하다. 번들러는 Vite ^8(+vite-plugin-electron), 패키징은 electron-builder ^26, 타입은 TypeScript ^7. 테스트는 별도 프레임워크(Jest/Vitest) 없이 Node 내장 테스트 러너(node --test + --experimental-transform-types)로 14개 *.test.ts를 돌린다. CI는 non-windows.yml·windows.yml·portable.yml 3종이고, Windows 워크플로는 windows-latest네이티브 windows-11-arm 이미지 모두에서 돈다. Dockerfile·서버는 없다.

인프라에서 배우는 것
"라이선스 미검토면 빌드 실패" — 컴플라이언스를 게이트로

Dockerfile 대신 이 레포엔 묵직한 컴플라이언스 서브시스템이 있다: third_party/compliance-policy.json, scripts/prepare-compliance.mjs, verify-packaged-compliance.mjs, 그리고 npm run compliance:licenses. 번들되는 패키지 중 하나라도 검토된 법적 문서가 없으면 빌드를 실패시킨다. Microsoft의 재배포 규칙(로컬 소스 빌드 vs 재배포 패키지의 경계)을 코드로 강제한 것 — 대기업이 오픈소스를 낼 때 어떻게 라이선스 리스크를 자동화하는지 보여주는 좋은 표본이다.

4아키텍처 심화 — 4단계 파이프라인과 결정론+LLM 분업

이 레포의 알맹이. 파이프라인 한 축, 그 위에 얹힌 설계 패턴 네 개

축 1 — Record → Process → Analyze → Create 파이프라인

녹화가 끝나면 electron/pipeline.tsprocessSession(dir)가 후처리를 한다. 설계 원칙이 코드 주석에 못박혀 있다: "OS 이벤트가 1차 신호, 영상은 부수적(opportunistic)""영상 전체를 스캔하지 않는다. 이벤트가 1차 신호이고, 이벤트가 놓친 것만 낮은 신뢰 구간에서 프로브 제안으로 나중에 수확한다." 즉 값싼 이벤트를 최대한 쓰고, 비싼 영상 분석은 최소로 아낀다.

┌─ 로컬(내 컴퓨터) ──────────────────────────────────────────┐ │ RECORD ⌘⇧R │ │ collectors ──▶ events.jsonl (app.activate / title / │ │ browser.url / clipboard / │ │ terminal.command / marker)│ │ + video.webm (1fps·저화질) + audio.webm(선택) │ │ │ │ │ ▼ processSession(dir) [pipeline.ts] │ │ PROCESS 1) readEvents() │ │ 2) 프레임 추출 (의미 이벤트마다 1장, dHash 중복제거) │ │ 3) buildBundle() → 이벤트를 "단계(step)"로 분절 │ │ 4) renderDescription() → description.md (결정론 초안)│ └───────────────────────────────────────────────────────────┘ │ ▲ 여기까지 아무것도 밖으로 안 나감 ▼ │ "Analyze" 클릭 → GitHub 클라우드 ┌─ 클라우드(GitHub Copilot) ─────────────────────────────────┐ │ ANALYZE Describer 에이전트 + 6개 샌드박스 도구 │ │ get_timeline / get_events / get_narration / │ │ list_frames / get_frames / submit_analysis │ │ → analysis.json {의도 1개 + 순서 있는 단계들} │ │ ↑ 사용자가 검토·수정, 자연어 피드백(세션 유지) │ │ ▼ │ │ CREATE SkillBuilder / AutomationBuilder (2단계 에이전트) │ │ propose_plan → (사용자 편집) → submit_skill │ │ → SKILL.md (~/.copilot/skills/ 또는 내보내기) │ └───────────────────────────────────────────────────────────┘

축 2 — 패턴①: 결정론적 코어 + LLM 가장자리

이 레포의 가장 배울 만한 설계다. 분절·상관 같은 "정답이 있는" 일은 순수 함수 + zod 검증 + 단위테스트로 결정론적으로 처리하고, "의도 재구성" 같은 애매한 일만 LLM에 맡긴다. 예컨대 이벤트를 단계로 쪼개는 common/bundle.ts(252줄)의 경계 규칙은 완전히 결정론적이다:

// common/bundle.ts — 어디서 새 "단계"가 시작되는가 (순수 규칙)
if (!cur) boundary = "start";
else if (ev.type === "app.activate" && app && app !== curApp) boundary = "app-change";
else if (ev.type === "browser.url" && host && host !== curHost) boundary = "url-change";
else if (ev.type === "terminal.command") boundary = "command";
// 그 외(제목 변경·클립보드·마커)는 현재 단계에 흡수

앱이 바뀌거나, 브라우저 호스트가 바뀌거나, 터미널 명령이 실행되면 새 단계가 열리고 나머지는 현재 단계에 folding된다. 그리고 renderDescription()이 만드는 description.mdCopilot이 없어도 나오는 결정론적 폴백이다. LLM은 "있으면 더 좋은" 가장자리일 뿐, 코어가 LLM에 종속되지 않는다.

용어
unexplained 프레임 · silent 이벤트 (correlation.ts)
common/correlation.ts(262줄)는 프레임과 이벤트를 ±1500ms로 맞춰 붙인다. 여기서 나오는 두 개념: unexplained 프레임 = 화면은 확 바뀌었는데 근처에 의미 이벤트가 없는 장면(이벤트 스트림이 놓친 미세 단계 후보). silent 이벤트 = 의미 이벤트는 있는데 시각적으로 구별되는 프레임이 안 나온 경우. 이걸로 "프로브 요청"을 만드는데, 비영상 신호가 풍부할수록 빈틈이 짧아 프로브가 줄어드는 자기 조절(self-scaling) 구조다.

축 3 — 패턴②: 도구 샌드박싱 (fail-closed 보안)

Describer(electron/describer/describer.ts, 430줄)는 하나의 CopilotClient를 쥐고, 피드백 맥락을 살리려 최대 MAX_LIVE_SESSIONS = 4개의 재개 가능 대화를 유지한다. 프레임이 이미지이므로 pickVisionModel()로 비전 지원 모델을 우선 고른다. 핵심은 에이전트가 볼 수 있는 도구를 커스텀 6종으로만 제한(allowlist)한다는 것:

// 커스텀 도구만 노출. 런타임이 allowlist를 못 지키면
// 조용히 무제한 세션을 만드느니 분석을 실패시킨다
// (approveAll과 겹치면 SDK 기본 도구가 사용자 환경에서 자동 실행될 위험)
const copilot = await client.createSession({
  ...config,
  availableTools: tools.map((t) => t.name),   // ← 화이트리스트
});

"실패하면 안전한 쪽으로(fail-closed)" 태도가 분명하다 — 샌드박스를 보장 못 하면 차라리 멈춘다. 만약 에이전트가 submit_analysis 호출을 잊으면 NUDGE_PROMPT가 강제로 마무리시키고, 턴 타임아웃은 180초다.

축 4 — 패턴③: 셸 없이 "눈"을 주는 인라인 이미지 도구

electron/describer/tools.ts(374줄)가 정의하는 6개 도구 중 get_frames의 트릭이 영리하다. 파일시스템이나 bash 도구를 주지 않고도 모델이 화면을 직접 보게 하려고, JPEG를 base64로 인라인 반환(binaryResultsForLlm)한다. 프레임은 MAX_IMAGES_PER_CALL = 6으로 균등 서브샘플, 이벤트는 MAX_EVENTS = 500, 모든 문자열은 2000자에서 절단한다. submit_analysis는 zod로 검증해 규격이 어긋나면 고칠 수 있는 오류 메시지를 돌려준다. CLI 에이전트에게 셸 권한 없이 시각을 부여하는 깔끔한 방법이다.

축 5 — 패턴④: 네이티브 도구 우선 + calculation/action 분리 + {{토큰}} 일반화

스킬 빌더(electron/skillbuilder/builder.ts, 360줄)는 2단계 에이전트다: propose_plan(사용자 검토를 위해 STOP) → submit_skill. 사용자가 편집한 계획이 권위(authoritative)를 가져, 에이전트는 본문만 쓸 수 있고 값·단계를 다시 추가·재배열할 수 없다. 여기에 세 가지 핵심 규율이 얹힌다:

그리고 이 모든 것의 목적인 일반화가 빌더 지시문에 못박혀 있다: "사용자가 특정 집합에 작용했다면(예: 시트 3개 행의 폼 제출), 스킬은 모든 항목(N)을 다뤄야 하며… 예시 3개를 하드코딩하지 않는다." 이것이 "폼 하나 → 폼 전부"를 만드는 규칙이다.

보너스 — 프레임 추출의 지각 해시 중복 제거

electron/frames/extractor.ts(627줄)는 프레임마다 64비트 dHash(차이 해시)를 계산해, 기존 프레임과 해밍 거리(Hamming distance)가 임계값 이하면 중복으로 버린다:

// 두 프레임의 dHash 해밍 거리가 임계값 이하면 중복
const DEFAULTS = { dedupeThreshold: 8, maxFrames: 300, frameGridSec: 0.5 };
...
const phash = await dhash(file);
if (hamming(existing.phash, phash) <= this.opts.dedupeThreshold) {
  /* 거의 같은 화면 → 버림 */
}

영상은 1fps·1280×720·500kbps로 일부러 낮게 잡는다. 주석에 이유가 있다: "화면 캡처의 진짜 비용은 WindowServer가 프레임버퍼를 잡는 것… 이건 이벤트에 앵커된 부수적 보강일 뿐, 아무도 안 보는 영상"이다. 값싼 신호(이벤트)를 주력으로, 비싼 신호(영상)를 절약하는 철학이 프레임 레이트에까지 일관된다.

5디렉토리 구조 해부

약 22,400줄. common(순수 계약) · electron(메인) · src(렌더러)로 관심사가 갈린다
skill-recorder/ ├─ common/ ~2,622줄 · 순수·공유·zod 검증 데이터 계약 (Electron 의존 0) │ ├─ events.ts 이벤트 타입 → 페이로드 스키마 │ ├─ bundle.ts ★ 이벤트를 "단계(step)"로 분절 (결정론) 252줄 │ ├─ correlation.ts 프레임↔이벤트 상관, unexplained/silent 탐지 262줄 │ ├─ analysis.ts describer의 출력 계약 (의도 + 단계) │ ├─ skill.ts ★ builder 출력 계약 + SKILL.md 렌더러 235줄 │ └─ narration.ts / audio.ts / values.ts(토큰 치환) / config.ts … │ ├─ electron/ ~10,049줄 · Electron 메인 프로세스 (앱의 본체) │ ├─ main.ts 앱 배선·3개 창·전역 단축키·정상 종료 314줄 │ ├─ pipeline.ts ★ 녹화 후처리 processSession() 112줄 │ ├─ recorder/ 컨트롤러(상태기계)·collector·session-store │ ├─ collectors/ active-window · clipboard · url-provider (OS별) │ ├─ frames/ extractor(dHash 중복제거) · correlate 627줄 │ ├─ video/ audio/ narration/ 캡처 + 온디바이스 Whisper 전사 │ ├─ describer/ ★ 의도·단계 재구성 Copilot 에이전트 430줄 │ │ ├─ describer.ts 샌드박스 세션·비전 모델·live 세션 관리 │ │ ├─ tools.ts 6개 인프로세스 도구(get_frames 인라인 이미지) 374줄 │ │ └─ instructions.ts 프롬프트(녹화 브라케팅 노이즈 필터 등) │ ├─ skillbuilder/ ★ → SKILL.md (scout/cowork 카탈로그) 360줄 │ ├─ automationbuilder/ → 예약 자동화 │ └─ builders/ 공유 AgentBuilder 베이스 + read-tools │ ├─ src/ ~3,732줄 · React 렌더러(UI) │ └─ Recorder.tsx · Library.tsx · plan-edit.tsx … │ ├─ evals/ 픽스처 기반 평가 하네스(describer + automation + skill) ├─ scripts/ 컴플라이언스 + Windows 패키징 검증 ├─ third_party/ compliance-policy.json (라이선스 게이트) └─ docs/ INSTALL.md · RELEASING.md · WINDOWS-VALIDATION.md …

구조가 알려주는 힌트 셋. 첫째, common/이 "순수 계약" 층으로 완전히 분리돼 Electron을 전혀 import하지 않는다 — 그래서 node --test로 단독 단위테스트가 가능하고, 결정론적 코어가 UI/OS와 얽히지 않는다. 둘째, electron/ 안이 수집(collectors) · 후처리(frames·pipeline) · 추론(describer·builders)으로 또 갈려 있어, 예컨대 새 수집기(터미널 명령 등)를 추가하거나 새 빌더(자동화 외)를 붙이기 쉽다. 셋째, evals/가 1급 시민이다 — describer/automation/skill 세 갈래를 합성 픽스처로 채점해, LLM 부분이 회귀하는지 CI로 지킨다.

구조에서 배우는 것
"순수 코어를 프레임워크에서 떼어내기"

common/이 Electron·React를 모른다는 건 우연이 아니다. 비즈니스 로직(분절·상관·스킬 렌더)을 UI/OS 프레임워크에서 분리하면, 테스트가 빨라지고, 나중에 Electron을 걷어내거나 CLI로 재포장하기도 쉽다. "핵심 규칙은 순수 함수로, 지저분한 I/O는 바깥 껍질로"라는 헥사고날/클린 아키텍처의 실전 예다. 규모가 작아도 이 경계를 지킨 게 이 레포의 완성도를 만든다.

6학습 포인트 — 기술별 배울 것

데스크탑 앱 하나에 "AI 에이전트 설계"의 실전 교훈이 촘촘하다

① 결정론적 코어 + LLM 가장자리 (가장 값진 배움)

"정답이 있는 일은 순수 코드로, 애매한 일만 LLM으로" 나누는 사고틀. 분절·상관·검증은 zod로 결정론화하고, 의도 재구성만 Copilot에 맡긴다. description.md라는 LLM 없는 폴백까지 둔 게 백미다. 이 패턴은 어떤 AI 기능에도 옮겨진다 — "이 기능에서 LLM이 정말 필요한 최소 지점은 어디인가"를 묻는 습관을 배운다.

② 에이전트 도구 샌드박싱과 fail-closed

availableTools allowlist로 에이전트가 볼 도구를 화이트리스트하고, 런타임이 이를 못 지키면 조용히 진행하지 않고 실패시키는 보안 태세. approveAll(자동 승인)과 겹칠 때의 위험을 코드 주석으로 명시한 것도 배울 점이다. LLM에게 도구를 쥐여줄 때 "최소 권한 + 실패 시 안전"을 어떻게 코드로 강제하는지의 표본이다.

③ CLI 에이전트에게 "시각" 주기

셸·파일 도구 없이도 모델이 화면을 보게 하는 법 — JPEG를 base64 인라인으로 도구 결과에 실어 반환. 이미지 6장 서브샘플·이벤트 500개·문자열 2000자 절단 같은 컨텍스트 예산 관리도 함께 배운다. 멀티모달 에이전트를 만들 때 "무엇을, 얼마나, 어떤 형태로 모델에 넣는가"의 실전이다.

④ 관찰 → 일반화 (RPA를 넘어서는 지점)

좌표 재생이 아니라 의미 이벤트 → 의도 → 네이티브 도구 매핑 → N건 일반화. "폼 하나 → 폼 전부", "클릭 → gh 호출"로 바꾸는 calculation/action 분리와 {{토큰}} 치환. 자동화 도구를 설계한다면 "녹화를 어떻게 견고하고 일반적인 절차로 승격시키나"가 핵심 질문이 된다.

⑤ 온디바이스 ML 통합 (transformers.js + Whisper)

클라우드로 오디오를 보내지 않고 브라우저/Node 런타임에서 Whisper를 직접 돌리는 법. 모델을 첫 사용 시 1회 다운로드(~252MB)해 캐시하고, GPU 없이 CPU ONNX로 99개 언어를 전사한다. "프라이버시가 중요한 기능은 온디바이스로"의 구체적 구현을 배운다.

⑥ 순수 코어 분리와 픽스처 기반 eval

common/을 프레임워크에서 떼어 node --test로 단독 검증하고, LLM 부분은 합성 픽스처 eval(describer/automation/skill 3종)로 회귀를 지키는 방식. "비결정적인 LLM 기능을 어떻게 CI로 지키나"라는 어려운 문제에 대한 실용적 답이다.

실습 아이디어(가볍게)
"의미 이벤트"만으로 내 작업을 스텝으로 쪼개 보기

앱을 설치하지 않아도 핵심 아이디어는 체험할 수 있다. 아무 반복 업무(예: 이슈 3개 닫기)를 하면서 "앱 전환 / URL 변경 / 복사 / 명령 실행"만 손으로 메모해 보라. 그 메모를 bundle.ts의 경계 규칙(app-change·url-change·command)대로 단계로 잘라 보면, "픽셀 없이 의미만으로도 절차가 복원되는" 감각과 "어디서 이벤트가 부족한지(unexplained 구간)"가 바로 보인다.

7시스템 / 실행 요구사항

실제로 설치해 스킬을 뽑아 보려면 무엇이 필요한가
항목필요한 것
플랫폼macOS가 1차 타깃. Windows 11(x64·ARM64) 지원, Ubuntu 설치 경로도 있음
AI 접근Copilot 접근 권한이 있는 GitHub 계정. Analyze/Create 시 데이터가 GitHub 클라우드로 감. Copilot CLI는 앱에 동봉
개발(소스 빌드)Node.js 24. npm cinpm run compliance:licensesnpm run dev(Vite+Electron 핫리로드)
macOS 권한Screen Recording(영상)·Accessibility(창 제목)·브라우저별 Automation(URL). 권한이 없으면 앱 전환 추적으로 우아하게 degrade
내레이션(선택)첫 사용 시 ~252MB Whisper-small int8 ONNX 모델 1회 다운로드(Xenova/whisper-small). 이후 오프라인·온디바이스, 99개 언어, GPU 불필요
설치 방식릴리스마다 커밋 고정(commit-pinned) 원라이너로, 검증된 Node 24 런타임을 받아 정확한 릴리스 커밋을 로컬에서 빌드. "전역 설치 없음(Nothing is installed globally)"

설치 명령은 릴리스 페이지에서 플랫폼별로 복사하는데, 커밋 해시가 박힌 형태다(개념 형태):

# macOS / Ubuntu — <40자 릴리스 커밋>은 릴리스 페이지에서 채워짐
commit="<40-character-release-commit>"
curl -fsSL "https://raw.githubusercontent.com/microsoft/skill-recorder/$commit/install.sh" \
  | SKILL_RECORDER_COMMIT="$commit" bash
# 백그라운드 유지: 파이프 뒤에 SKILL_RECORDER_DETACHED=1 추가
# → macOS는 ~/Applications 에 "Skill Recorder (Source)" 앱을 추가
주의
v0.3 초기 단계 · 대상 에이전트가 한정적

버전이 0.3.1초기 프로젝트다. 산출된 스킬의 목표 아키텍처는 Scout·Cowork(M365 Copilot)가 활성이고 copilot-studio는 "coming soon" 상태다. 즉 임의의 아무 에이전트에나 바로 꽂히는 범용 포맷이라기보다, Microsoft/GitHub 생태계(Copilot·Scout·M365)에 최적화돼 있다. SKILL.md 자체는 열린 포맷이지만, "네이티브 도구 우선" 매핑은 그 카탈로그(gh·web_fetch·workiq_*)에 묶여 있음을 감안해야 한다.

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

난이도별로. 앱을 설치 안 해도 상당수는 소스·개념만으로 가능하다
과제 1 난이도 ●○○○○

파이프라인 4단계를 소스에서 추적해 지도 그리기

git clone --depth 1로 받아 electron/pipeline.tsprocessSession()을 읽고, Record→Process→Analyze→Create가 어떤 파일·함수로 이어지는지 한 장으로 그린다. 특히 "어디까지가 로컬이고 어디서 클라우드로 나가는가"의 경계를 표시하라. "왜 description.md를 결정론으로 먼저 만들까?"에 스스로 답하는 게 목표.

과제 2 난이도 ●●○○○

bundle.ts 경계 규칙으로 내 작업 로그를 단계로 쪼개기

종이에 아무 반복 업무의 "앱 전환 / URL / 복사 / 명령"을 시간순으로 적은 뒤, common/bundle.ts의 규칙(app-change·url-change·command가 새 단계, 나머지는 흡수)을 손으로 적용해 단계로 나눠 보라. 같은 로그를 규칙 없이 나눈 것과 비교해, 결정론적 분절이 왜 재현 가능한지 체감한다.

과제 3 난이도 ●●●○○

SKILL.md를 손으로 써서 에이전트에 물려 보기

이 앱 없이도 결과물 포맷은 흉내 낼 수 있다. common/skill.ts의 렌더 규칙(YAML name·description·allowed-tools + 본문, {{토큰}} 값)을 참고해, 자기 반복 업무 하나를 SKILL.md로 직접 작성한다. 값(URL 등)은 {{repo}}처럼 토큰화하고, 단계를 calculation/action으로 표시해 보라. Claude Code·Copilot에 넣어 실제로 도는지 확인.

과제 4 난이도 ●●●●○

dHash 프레임 중복 제거 재현하기

화면 녹화 mp4 하나를 ffmpeg로 0.5초 간격 프레임으로 뽑은 뒤, 파이썬 imagehash(dHash)로 인접 프레임의 해밍 거리를 구해 임계값 8 이하를 버리는 스크립트를 짠다. 원본 프레임 수 대비 얼마나 줄어드는지 세어, extractor.ts가 왜 "화면이 바뀔 때만" 프레임을 남기는지 데이터로 확인하라.

과제 5 난이도 ●●●●●

"관찰 → 일반화" 미니 에이전트 만들기

작은 도전: JSON 이벤트 로그(앱·URL·클립보드)를 입력받아 LLM에게 "의도 1개 + 순서 있는 단계"로 재구성시키되, 도구를 화이트리스트로 제한하고 출력은 스키마(zod/JSON Schema)로 검증하는 파이프라인을 직접 구현한다. 그리고 "예시 3건 → N건 일반화" 지시를 프롬프트에 넣어, 하드코딩 없이 일반 절차가 나오는지 eval 픽스처 2~3개로 채점해 보라. skill-recorder의 축소판을 만드는 과제.

9관련 기술 심화 로드맵 (주차별)

이 레포를 계기로 "AI 에이전트 저작·자동화"를 공부한다면
주차주제구체적으로
1주에이전트 스킬 포맷SKILL.md 규격(YAML 머리말·description 트리거·allowed-tools), Claude/Copilot 스킬 생태계, "스킬을 언제·어떻게 자동 로드하나"
2주결정론 코어 + LLM 가장자리zod로 데이터 계약 세우기, 순수 함수 분절/상관, LLM 폴백 설계. "LLM이 정말 필요한 최소 지점" 찾기
3주도구 사용 에이전트 & 샌드박싱function calling, availableTools allowlist, fail-closed, 인라인 멀티모달(이미지) 도구, 컨텍스트 예산(서브샘플·절단)
4주관찰→일반화 & RPA 비교의미 이벤트 vs 좌표 재생, 네이티브 도구 매핑(gh·web_fetch), calculation/action, {{토큰}} 일반화. UiPath/Playwright codegen과 대조
5주온디바이스 MLtransformers.js + Whisper, ONNX Runtime, 모델 양자화(int8), CPU 추론, 프라이버시 우선 기능 설계
6주(선택)Electron 앱 + 공급망메인/렌더러 분리, 전역 단축키·화면 캡처 권한, 커밋 고정 소스 릴리스, 라이선스 컴플라이언스 게이트

10핵심 키워드 사전

이 문서에 나온 개념 압축 정리
용어
에이전트 스킬 (SKILL.md)
YAML 머리말(name·description·allowed-tools)+마크다운 본문으로 된 "AI 작업 매뉴얼". 에이전트가 description을 보고 맞는 상황에 절차를 실행한다. skill-recorder의 최종 산출물.
용어
의미 이벤트 (semantic OS event)
키스트로크·마우스 좌표가 아니라 "어떤 앱, 어떤 URL, 무엇을 복사, 어떤 명령"처럼 뜻이 담긴 신호. app.activate / browser.url / clipboard.change / terminal.command / marker 등. 값싸고 견고하다.
용어
결정론적 코어 + LLM 가장자리
정답 있는 일(분절·상관·검증)은 순수 함수+zod로 결정론화하고, 애매한 일(의도 재구성)만 LLM에 맡기는 설계. description.md라는 LLM 없는 폴백까지 둔다. 이 레포의 핵심 패턴.
용어
단계 분절 (bundle.ts)
이벤트 스트림을 "단계(step)"로 자르는 결정론 규칙. app-change·url-change·command에서 새 단계가 열리고 나머지(제목·클립보드·마커)는 흡수된다.
용어
unexplained 프레임 / silent 이벤트
correlation.ts 개념. 화면은 바뀌었는데 이벤트가 없으면 unexplained(놓친 미세 단계 후보), 이벤트는 있는데 시각 변화가 없으면 silent. 비영상 신호가 풍부할수록 프로브가 줄어드는 자기 조절 구조.
용어
도구 샌드박싱 (availableTools allowlist)
Copilot 세션이 볼 수 있는 도구를 커스텀 6종으로 화이트리스트. 런타임이 이를 못 지키면 조용히 진행 않고 분석을 실패(fail-closed). approveAll과 겹칠 때의 위험을 차단.
용어
인라인 이미지 도구 (get_frames)
셸·파일 도구 없이 모델에 "시각"을 주는 방법. JPEG를 base64로 도구 결과에 실어 반환(binaryResultsForLlm). 이미지 6장·이벤트 500개·문자열 2000자로 컨텍스트를 예산화.
용어
네이티브 도구 우선 (native-tools-first)
녹화된 UI 클릭을 재생하지 않고 gh CLI·web_fetch·M365 API 같은 정식 도구 호출로 매핑. 버전 관리되는 능력 카탈로그(scout-catalog.ts)에 근거. 브라우저/Playwright는 최후 수단.
용어
일반화 · {{토큰}} · calculation/action
예시 하나(폼 3건)를 N건으로 승격(하드코딩 금지). 고정 값은 {{id}} 토큰으로 빼 편집 가능하게, 단계는 부수효과 없는 calculation과 세상을 바꾸는 action(제출·삭제=위험 표면)으로 분리.
용어
dHash 지각 해시 / 해밍 거리
프레임을 64비트 차이 해시로 요약해 인접 프레임과 해밍 거리(다른 비트 수)가 임계값(8) 이하면 중복으로 버리는 기법. "화면이 바뀔 때만" 프레임을 남겨 저장·전송을 아낀다.
용어
온디바이스 Whisper (transformers.js)
내레이션을 클라우드로 보내지 않고 내 컴퓨터에서 전사. 첫 사용 시 ~252MB int8 ONNX 모델 1회 다운로드, 이후 오프라인·99개 언어·GPU 불필요(CPU ONNX Runtime).

11참고 링크

더 파고들 때