Communitygithub.com

Windows-데스크톱-E2E

pywinauto와 Windows UI Automation을 사용하여 WPF, WinForms, Win32/MFC, Qt와 같은 Windows 네이티브 데스크톱 앱을 위한 E2E 테스트입니다. pywinauto 또는 UI Automation을 사용하여 Windows 네이티브 데스크톱 앱의 E2E 테스트를 작성할 때 활성화하세요.

Windows-데스크톱-E2E란 무엇인가요?

이 스킬은 Windows UI Automation(UIA)을 백엔드로 사용하는 pywinauto 라이브러리를 기반으로 Windows 네이티브 데스크톱 애플리케이션을 위한 종단간(E2E) 테스트 자동화를 제공합니다. WPF, WinForms, Win32/MFC, Qt(5.x/6.x) 등 주요 Windows GUI 프레임워크를 지원하며, 각 프레임워크에 맞는 테스트 용이성 설정(예: AutomationId 부여)을 안내합니다. 페이지 객체 모델(Page Object Model)을 기반으로 한 구조화된 테스트 코드를 제공하여 유지보수성을 높이고, 안정적인 로케이터 전략(AutomationId 우선), 지능형 대기 패턴(flaky 방지), 아티팩트 관리(스크린샷, 비디오 녹화), 선택적 단계별 추적 기능을 포함합니다. GitHub Actions의 windows-latest 환경에서 CI/CD 통합을 지원하며, 특히 Qt 5.x의 경우 환경 변수 설정을 통해 UIA를 활성화하는 방법을 명시합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/windows-desktop-e2e

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Windows 데스크톱 E2E 테스트

pywinauto와 Windows UI Automation(UIA)을 백엔드로 사용하여 Windows 네이티브 데스크톱 애플리케이션의 종단간(E2E) 테스트를 수행합니다. WPF, WinForms, Win32/MFC, Qt(5.x/6.x)를 지원하며, Qt 관련 지침은 별도의 섹션으로 제공됩니다.

활성화 시기

  • Windows 네이티브 데스크톱 애플리케이션에 대한 E2E 테스트 작성 또는 실행
  • 데스크톱 GUI 테스트 스위트를 처음부터 구축
  • 불안정하거나 실패하는 데스크톱 자동화 테스트 진단
  • 기존 앱에 테스트 용이성(AutomationId, 접근 가능한 이름) 추가
  • CI/CD 파이프라인(GitHub Actions windows-latest)에 데스크톱 E2E 통합

사용하지 말아야 할 경우

  • 웹 애플리케이션 → e2e-testing 스킬(Playwright) 사용
  • Electron / CEF / WebView2 앱 → HTML 레이어는 브라우저 자동화가 필요하며 UIA가 적합하지 않음
  • 모바일 앱 → 플랫폼별 도구(UIAutomator, XCUITest) 사용
  • 실행 중인 GUI가 필요 없는 순수 단위 또는 통합 테스트

핵심 개념

모든 Windows 데스크톱 자동화는 Windows에 내장된 접근성 API인 **UI Automation(UIA)**에 의존합니다. 지원되는 모든 프레임워크는 Claude가 읽고 조작할 수 있는 속성을 가진 UIA 요소 트리를 노출합니다.

사용자 테스트 (Python)
    └── pywinauto (UIA 백엔드)
        └── Windows UI Automation API   ← Windows에 내장, 프레임워크 독립적
            └── 앱의 UIA 공급자         ← 각 프레임워크가 자체 제공
                └── 실행 중인 .exe

프레임워크별 UIA 품질:

프레임워크AutomationId신뢰성참고 사항
WPF5/5우수함x:Name이 AutomationId에 직접 매핑됨
WinForms4/5좋음AccessibleName = AutomationId
UWP / WinUI 35/5우수함Microsoft의 완전한 지원
Qt 6.x5/5우수함접근성이 기본적으로 활성화됨; 클래스 이름이 Qt6*로 변경됨
Qt 5.15+4/5좋음개선된 접근성 모듈
Qt 5.7–5.143/5보통QT_ACCESSIBILITY=1 필요; objectName 수동 설정
Win32 / MFC3/5보통컨트롤 ID 접근 가능; 텍스트 일치 방식 일반적

설정 및 전제 조건

# Python 3.8+, Windows 전용
pip install pywinauto pytest pytest-html Pillow pytest-timeout
# 선택 사항: 화면 녹화
# ffmpeg를 설치하고 PATH에 추가: https://ffmpeg.org/download.html

UIA에 연결할 수 있는지 확인:

from pywinauto import Desktop
Desktop(backend="uia").windows()  # 모든 최상위 창 나열

Accessibility Insights for Windows(무료, Microsoft 제공)를 설치하세요. 테스트를 작성하기 전에 UIA 요소 트리를 검사할 수 있는 DevTools와 같은 도구입니다.

테스트 용이성 설정 (프레임워크별)

테스트 작성을 시작하기 전에 가장 중요한 것은 모든 대화형 컨트롤에 안정적인 AutomationId를 부여하는 것입니다.

WPF

<!-- XAML: x:Name이 자동으로 AutomationId가 됨 -->
<TextBox x:Name="usernameInput" />
<PasswordBox x:Name="passwordInput" />
<Button x:Name="btnLogin" Content="로그인" />
<TextBlock x:Name="lblError" />

WinForms

// 디자이너 또는 코드에서 설정
usernameInput.AccessibleName = "usernameInput";
passwordInput.AccessibleName = "passwordInput";
btnLogin.AccessibleName = "btnLogin";
lblError.AccessibleName = "lblError";

Win32 / MFC

// .rc 파일의 컨트롤 리소스 ID가 AutomationId 문자열로 노출됨
// IDC_EDIT_USERNAME -> AutomationId "1001"
// Name 설정에는 SetWindowText를 선호; 더 풍부한 지원을 위해 IAccessible 추가

Qt — 아래 전용 섹션 참조


페이지 객체 모델

tests/
├── conftest.py          # 앱 실행 fixture, 실패 스크린샷
├── pytest.ini
├── config.py
├── pages/
│   ├── __init__.py      # 임포트에 필요
│   ├── base_page.py     # 로케이터, 대기, 스크린샷 도우미
│   ├── login_page.py
│   └── main_page.py
├── tests/
│   ├── __init__.py
│   ├── test_login.py
│   └── test_main_flow.py
└── artifacts/           # 스크린샷, 비디오, 로그

base_page.py

import os, time
from pywinauto import Desktop
from config import ACTION_TIMEOUT, ARTIFACT_DIR

class BasePage:
    def __init__(self, window):
        self.window = window

    # --- 로케이터 (우선순위 순서) ---

    def by_id(self, auto_id, **kw):
        """AutomationId — 가장 안정적임. 첫 번째 선택으로 사용."""
        return self.window.child_window(auto_id=auto_id, **kw)

    def by_name(self, name, **kw):
        """표시되는 텍스트 / 접근 가능한 이름."""
        return self.window.child_window(title=name, **kw)

    def by_class(self, cls, index=0, **kw):
        """컨트롤 클래스 + 인덱스 — 취약하므로 가능하면 피할 것."""
        return self.window.child_window(class_name=cls, found_index=index, **kw)

    # --- 대기 ---

    def wait_visible(self, spec, timeout=ACTION_TIMEOUT):
        spec.wait("visible", timeout=timeout)
        return spec

    def wait_gone(self, spec, timeout=ACTION_TIMEOUT):
        spec.wait_not("visible", timeout=timeout)
        return spec

    def wait_window(self, title, timeout=ACTION_TIMEOUT):
        """새 최상위 창(대화상자, 자식 창)을 기다림."""
        dlg = Desktop(backend="uia").window(title=title)
        dlg.wait("visible", timeout=timeout)
        return dlg

    def wait_until(self, fn, timeout=ACTION_TIMEOUT, interval=0.3):
        """임의 조건을 폴링 — UIA 이벤트가 신뢰할 수 없을 때 사용."""
        deadline = time.time() + timeout
        while time.time() < deadline:
            try:
                if fn():
                    return True
            except Exception:
                pass
            time.sleep(interval)
        raise TimeoutError(f"{timeout}초 내에 조건이 충족되지 않음")

    # --- 동작 ---

    def click(self, spec):
        self.wait_visible(spec)
        spec.click_input()

    def type_text(self, spec, text):
        self.wait_visible(spec)
        ctrl = spec.wrapper_object()
        try:
            ctrl.set_edit_text(text)
        except Exception as e:
            # Qt 5.x 대체: UIA 값 패턴이 불완전할 수 있음
            import sys, pywinauto.keyboard as kb
            print(f"[windows-desktop-e2e] set_edit_text 실패 ({e}), 키보드 대체 사용", file=sys.stderr)
            ctrl.click_input()
            kb.send_keys("^a")
            kb.send_keys(text, with_spaces=True)

    def get_text(self, spec):
        ctrl = spec.wrapper_object()
        for attr in ("window_text", "get_value"):
            try:
                v = getattr(ctrl, attr)()
                if v:
                    return v
            except Exception:
                pass
        return ""

    # --- 아티팩트 ---

    def screenshot(self, name):
        os.makedirs(ARTIFACT_DIR, exist_ok=True)
        path = os.path.join(ARTIFACT_DIR, f"{name}.png")
        self.window.capture_as_image().save(path)
        return path

login_page.py

from pages.base_page import BasePage

class LoginPage(BasePage):
    @property
    def username(self): return self.by_id("usernameInput")

    @property
    def password(self): return self.by_id("passwordInput")

    @property
    def btn_login(self): return self.by_id("btnLogin")

    @property
    def error_label(self): return self.by_id("lblError")

    def login(self, user, pwd):
        self.type_text(self.username, user)
        self.type_text(self.password, pwd)
        self.click(self.btn_login)

    def login_ok(self, user, pwd, main_title="메인 창"):
        self.login(user, pwd)
        return self.wait_window(main_title)

    def login_fail(self, user, pwd):
        self.login(user, pwd)
        self.wait_visible(self.error_label)
        return self.get_text(self.error_label)

conftest.py

새 프로젝트의 경우 Tier 1 샌드박스 fixture(아래 참조)를 선호하세요. 추가 비용 없이 파일 시스템 격리를 제공합니다. 이 기본 fixture는 최소/레거시 설정에만 사용하세요.

import os, pytest
os.environ["QT_ACCESSIBILITY"] = "1"  # Qt 5.x UIA 지원에 필요

from pywinauto import Application
from config import APP_PATH, MAIN_WINDOW_TITLE, LAUNCH_TIMEOUT, ARTIFACT_DIR

@pytest.fixture
def app(request):
    if not APP_PATH:
        pytest.exit("APP_PATH 환경 변수가 설정되지 않았습니다", returncode=1)
    proc = Application(backend="uia").start(APP_PATH, timeout=LAUNCH_TIMEOUT)
    win  = proc.window(title=MAIN_WINDOW_TITLE)
    win.wait("visible", timeout=LAUNCH_TIMEOUT)
    yield win
    # 실패 시 스크린샷
    if getattr(getattr(request.node, "rep_call", None), "failed", False):
        os.makedirs(ARTIFACT_DIR, exist_ok=True)
        try:
            win.capture_as_image().save(
                os.path.join(ARTIFACT_DIR, f"FAIL_{request.node.name}.png")
            )
        except Exception:
            pass
    # 먼저 정상 종료 시도, 실패 시 강제 종료
    # proc은 pywinauto Application 객체 — wait_for_process() 대신 wait_for_process_exit() 사용
    try:
        win.close()
        proc.wait_for_process_exit(timeout=5)
    except Exception:
        proc.kill()

@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    outcome = yield
    setattr(item, f"rep_{outcome.get_result().when}", outcome.get_result())

config.py

import os
APP_PATH          = os.environ.get("APP_PATH", "")           # 환경 변수로 설정 — 기본 경로 없음
MAIN_WINDOW_TITLE = os.environ.get("APP_TITLE", "")
LAUNCH_TIMEOUT    = int(os.environ.get("LAUNCH_TIMEOUT", "15"))
ACTION_TIMEOUT    = int(os.environ.get("ACTION_TIMEOUT", "10"))
ARTIFACT_DIR      = os.path.join(os.path.dirname(__file__), "artifacts")

pytest.ini

[pytest]
testpaths = tests
markers =
    smoke: 주요 경로에 대한 빠른 smoke 테스트
    flaky: 알려진 불안정 테스트
addopts = -v --tb=short --html=artifacts/report.html --self-contained-html

로케이터 전략

AutomationId  >  Name (text)  >  ClassName + index  >  XPath
  (안정적)         (가독성)           (취약)              (최후의 수단)

Accessibility Insights로 검사 → Properties 창 → 먼저 AutomationId를 찾습니다.

# 런타임에 검사 — REPL에 붙여넣어 트리 탐색
win.print_control_identifiers()
# 또는 범위 좁히기:
win.child_window(auto_id="groupBox1").print_control_identifiers()

대기 패턴

# 컨트롤이 나타날 때까지 대기
page.wait_visible(page.by_id("statusLabel"))

# 컨트롤이 사라질 때까지 대기 (예: 로딩 스피너)
page.wait_gone(page.by_id("spinnerOverlay"))

# 대화상자가 나타날 때까지 대기
dlg = page.wait_window("삭제 확인")

# 사용자 지정 조건 (예: 텍스트 변경)
page.wait_until(lambda: page.get_text(page.by_id("lblStatus")) == "준비")

기본 동기화로 time.sleep()을 절대 사용하지 마세요 — wait() 또는 wait_until()을 사용하세요.

아티팩트 관리

# 요청 시 스크린샷
page.screenshot("로그인_후")

# 전체 화면 캡처 (창이 화면 밖에 있거나 최소화된 경우)
import pyautogui
pyautogui.screenshot("artifacts/fullscreen.png")

# ffmpeg로 화면 녹화 (테스트 전 시작, 테스트 후 중지)
import subprocess

def start_recording(name):
    return subprocess.Popen([
        "ffmpeg", "-f", "gdigrab", "-framerate", "10",
        "-i", "desktop", "-y", f"artifacts/videos/{name}.mp4"
    ], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

def stop_recording(proc):
    proc.stdin.write(b"q"); proc.stdin.flush(); proc.wait(timeout=10)

단계별 추적 (선택 사항)

기본 실패 스크린샷만으로는 불안정한 테스트를 진단하기에 충분하지 않은 경우가 많습니다. 아래 단계 수준 추적은 기본적으로 비활성화되어 있습니다. 불안정한 사례를 재현할 때만 활성화하세요.

활성화

E2E_TRACE=1 pytest tests/test_login.py -v
# JSONL 로그에 입력된 텍스트 포함 (자격 증명/PII를 입력하는 테스트에는 사용하지 마세요):
E2E_TRACE=1 E2E_TRACE_INCLUDE_TEXT=1 pytest ...

BasePage에 패치

import os, json, time
TRACE_ENABLED      = os.environ.get("E2E_TRACE") == "1"
TRACE_INCLUDE_TEXT = os.environ.get("E2E_TRACE_INCLUDE_TEXT") == "1"

class BasePage:
    _step = 0

    def _trace(self, action, spec=None, text=None):
        if not TRACE_ENABLED:
            return
        BasePage._step += 1
        idx = f"{BasePage._step:03d}"
        os.makedirs(ARTIFACT_DIR, exist_ok=True)
        try:
            self.window.capture_as_image().save(
                os.path.join(ARTIFACT_DIR, f"step_{idx}_{action}.png"))
        except Exception:
            pass  # 캡처 실패는 테스트를 중단하지 않아야 함
        rec = {
            "ts": time.time(), "step": BasePage._step, "action": action,
            "locator": getattr(spec, "criteria", None),
            "text": text if TRACE_INCLUDE_TEXT else ("<redacted>" if text else None),
        }
        with open(os.path.join(ARTIFACT_DIR, "trace.jsonl"), "a") as f:
            f.write(json.dumps(rec) + "\n")

    def click(self, spec):
        self.wait_visible(spec); self._trace("click_before", spec)
        spec.click_input();      self._trace("click_after",  spec)

    def type_text(self, spec, text):
        self.wait_visible(spec); self._trace("type_before", spec, text)
        # ... 기존 set_edit_text / 키보드 대체 ...
        self._trace("type_after", spec)

주의 사항

  • PII / 자격 증명: type_text 내용은 기본적으로 <redacted>로 처리됩니다. 로그인 또는 결제 흐름에서는 절대 E2E_TRACE_INCLUDE_TEXT=1를 설정하지 마세요.
  • 오버헤드: 동작당 약 50~200ms + 디스크에 단계당 PNG 하나. 기본 CI 매트릭스에서는 활성화하지 말고 전용 불안정 재현 작업에서만 사용하세요.
  • 아티팩트 증가: 긴 흐름은 수십 MB를 생성합니다. 그에 따라 retention-days를 조정하세요.
  • 병렬/재실행 위생: 이 간단한 예제는 trace.jsonl에 추가하고 클래스 수준 카운터를 사용합니다. 재실행 전에 아티팩트 디렉토리를 비우고 병렬 테스트를 위해 작업자별 아티팩트 디렉토리를 사용하세요.
  • 커버리지 격차: BasePage 외부(테스트 코드의 원시 pywinauto 호출)에서 수행된 동작은 추적되지 않습니다.

불안정한 테스트 처리

# 격리 — Playwright의 test.fixme()와 동일
@pytest.mark.skip(reason="불안정: 느린 CI에서 애니메이션 경합. 이슈 #42")
def test_animated_transition(self, app): ...

CI에서만 불안정한 테스트는 환경 변수 기반 조건부 스킵을 사용하세요:

import os

@pytest.mark.skipif(
    os.environ.get("CI") == "true",
    reason="로컬 전용: CI에서 불안정 (이슈 #89)"
)
def test_high_dpi_interaction(self, app): ...

Qt 특화 지침

Qt 5.x 및 6.x 모두 pywinauto UIA 백엔드를 지원하지만 중요한 차이점이 있습니다.

Qt 5.x 준비

# conftest.py 상단에 추가
import os
os.environ["QT_ACCESSIBILITY"] = "1"  # Qt 5.x는 명시적 활성화 필요
os.environ["QT_LINUX_ACCESSIBILITY_ALWAYS_ON"] = "1"  # Qt 5.15+ Linux

Qt 5.12 이하: objectName이 AutomationId로 노출됩니다.

Qt 5.15+ / 6.x

Qt 5.15부터 접근성 모듈이 기본적으로 활성화됩니다. Qt 6.x는 접근성을 기본적으로 활성화하며 클래스 이름이 Qt6*로 시작합니다.

# Qt 5.x vs 6.x 클래스 이름 확인
win.print_control_identidents()
# Qt6Window, Qt6Edit 등 찾기

Qt 공통 문제 해결

  1. 컨트롤이 표시되지 않음? QT_ACCESSIBILITY=1이 앱 시작 전에 설정되었는지 확인하세요.
  2. 편집 상자에 입력할 수 없음? Qt 5.x에서는 UIA 값 패턴이 불완전할 수 있습니다. 위의 type_text 대체(키보드 전송)를 사용하세요.
  3. Qt 6.x 클래스 이름? Qt 6은 클래스 이름 앞에 Qt6를 붙입니다(예: Qt6Window, Qt6Edit). 테스트를 업데이트하거나 print_control_identidents()로 확인하세요.
  4. objectName이 비어 있음? QWidget::setObjectName()을 호출하여 objectName을 설정하거나 Qt 5.x Designer UI 양식에서 설정하세요.

PySide6 / PyQt6 통합 테스트 모범 사례

import os
os.environ["QT_ACCESSIBILITY"] = "1"

from PySide6.QtWidgets import QApplication, QMainWindow, QLineEdit, QPushButton, QLabel
from pywinauto import Application

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("테스트 앱")
        self.username = QLineEdit(self, objectName="usernameInput")
        self.password = QLineEdit(self, objectName="passwordInput")
        self.btn = QPushButton("로그인", self, objectName="btnLogin")
        self.lbl = QLabel("", self, objectName="lblError")

# conftest.py에서
app = QApplication.instance() or QApplication([])
win = MainWindow(); win.show()

# pywinauto로 연결
proc = Application(backend="uia").connect(title="테스트 앱")

CI/CD 통합 (GitHub Actions)

# .github/workflows/e2e.yml 예제
name: 데스크톱 E2E
on: [push, pull_request]

jobs:
  test:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: |
          pip install pywinauto pytest pytest-html Pillow
      - run: |
          $env:APP_PATH = "path\\to\\your\\app.exe"
          $env:APP_TITLE = "앱 창 제목"
          pytest tests/ --html=artifacts/report.html --self-contained-html
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: e2e-artifacts
          path: artifacts/

모범 사례 요약

  1. 항상 AutomationId 사용 — 가장 안정적인 로케이터입니다.
  2. time.sleep() 대신 wait_ 사용* — 동기화 기본입니다.
  3. 실패 시 스크린샷 캡처 — CI 디버깅에 매우 유용합니다.
  4. 로컬에서 Accessibility Insights로 검사 — 첫 번째 테스트 전에 UIA 트리를 이해하세요.
  5. 페이지 객체 모델 사용 — 모든 프레임워크에서 테스트를 유지 관리하기 쉽게 만듭니다.
  6. CI에서 불안정한 테스트 격리 — 환경 변수 또는 pytest 마커를 사용하세요.
  7. Qt는 명시적으로 활성화 — QT_ACCESSIBILITY=1을 잊지 마세요.
  8. 추적을 드물게 사용 — 불안정한 재현 중에만 활성화하세요.
  9. 가상 데스크톱에서 병렬 실행 — 테스트 격리를 위해 Windows 샌드박스 또는 Docker Desktop을 사용하세요.
  10. Accessibility Insights로 실제 사용자처럼 탐색 — 클릭에 의존하지 마세요.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

관련 스킬