Recipes

CUAWright와 Hermes 에이전트 스킬을 활용한 브라우저 및 데스크톱 작업 자동화

README 링크에서 발견 · 2 days ago

Research & KnowledgeSoftware & DevOps

코딩 모델을 터미널을 통해 재사용 가능한 브라우저 및 데스크톱 에이전트로 전환

What they did

이들은 CUAWright(이전 명칭 Webwright)를 터미널 기반 하네스로 구축하여, 코딩 모델이 한 번에 하나의 클릭을 예측하는 대신 Playwright 브라우저 세션을 실행하고 페이지를 검사하며 스크립트를 작성할 수 있도록 했다. 브라우저 작업에는 `cuawright web`을, Ubuntu VM 데스크톱 작업에는 `cuawright desktop`을 사용했으며, 브라우저 세션이 아닌 워크스페이스(코드와 로그)를 영속 상태로 유지했다. 공유 `skills/cuawright-web/` 폴더를 플러그인/스킬로 설치하여 기존 에이전트(Hermes, 그리고 이와 동등하게 Claude Code 또는 Codex)가 브라우저 작업을 위해 CUAWright를 호출할 수 있도록 했다. 작업이 성공한 후에는 선택적인 Skill Factory를 실행하여 해결 과정을 파라미터화되고 검증된 스크립트로 정제했으며, 이 스크립트는 모델 없이 독립적으로 재실행된다. 또한 Task2UI 모드를 실험하여 작업 결과를 재사용 가능한 작은 HTML 앱으로 렌더링했다.

How it went

워크플로는 약 40초 만에 토큰 소모 없이 실행되는 재실행 가능한 Playwright 스크립트를 생성했으며, 프로젝트 측은 재사용을 통해 held-out WebArena 정확도가 55%에서 70%로 향상되었다고 보고합니다. 인용된 브라우저 벤치마크는 Online-Mind2Web에서 88.1%, Odysseys에서 77.5%입니다. 완성도는 연구용 도구로서 양호한 편입니다: 약 1.5k LoC, OpenAI/Anthropic/OpenRouter 백엔드, 그리고 하위 호환되는 `webwright` 명령과 임포트를 갖추고 있습니다.

Worth knowing

데스크톱 작업은 Ubuntu VM과 docs/desktop.md에 따른 별도 설정이 필요하므로 macOS나 Windows 호스트에서는 바로 사용할 수 없습니다. Skill Factory는 선택 사항이며 재사용 이점은 작업 유사성에 따라 달라집니다. 모델 백엔드에는 API 키가 필요하고, 장기 실행 신뢰성은 여전히 기반 코딩 모델에 의존합니다. 플러그인 설치 경로는 호스트 에이전트마다 다릅니다.

Wiring

CUAWright(Python >=3.10)와 Playwright Chromium을 설치합니다. OpenAI, Anthropic 또는 OpenRouter용 백엔드 키를 설정합니다. 브라우저 작업에는 `cuawright web`을, Ubuntu VM 데스크톱 작업에는 `cuawright desktop`을 사용합니다. 레거시 `webwright` 명령과 임포트도 여전히 동작합니다. 공유 `skills/cuawright-web/` 폴더를 호스트 에이전트(Hermes, Claude Code, 또는 `/plugin install cuawright@cuawright`를 통한 Codex)에 등록합니다. 에이전트는 터미널 명령을 실행하고, Playwright 세션을 생성하며, 스크립트와 로그를 워크스페이스에 작성하고, 실패 시 반복적으로 재시도합니다. 선택적으로 Skill Factory를 활성화하여 성공적인 해결을 검증된 매개변수화 스크립트로 변환하고, Task2UI를 통해 결과를 HTML 앱으로 렌더링할 수 있습니다.

Try it yourself

# CUAWright를 브라우저 자동화 하네스로 설정하기

## 1. 패키지 설치

```bash
npm install cuawright
# 또는
pip install cuawright
```

## 2. 백엔드 키 설정

OpenAI 또는 Anthropic 중 하나를 선택해 환경 변수로 설정합니다.

```bash
# OpenAI 사용 시
export OPENAI_API_KEY="sk-..."

# Anthropic 사용 시
export ANTHROPIC_API_KEY="sk-ant-..."
```

프로젝트 루트의 `.env` 파일에 저장하는 것을 권장하며, `.gitignore`에 반드시 추가하세요.

## 3. 스킬 폴더 등록

`skills/cuawright-web` 폴더를 에이전트 스킬로 등록합니다. 에이전트 설정 파일(예: `agent.config.json` 또는 `skills.json`)에 다음 항목을 추가하세요.

```json
{
  "skills": [
    {
      "name": "cuawright-web",
      "path": "skills/cuawright-web",
      "description": "Browser automation via CUAWright for web navigation, form filling, and screenshots"
    }
  ]
}
```

## 4. 스크립트 작성

`scripts/demo-login-form.ts` 파일을 생성합니다.

```typescript
import { cuawright } from "cuawright";
import { writeFileSync } from "fs";

interface RunOptions {
  date: string;          // 예: "2025-06-15"
  outputDir?: string;
}

export async function runDemoFlow({ date, outputDir = "artifacts" }: RunOptions) {
  const browser = await cuawright.launch({ headless: true });
  const page = await browser.newPage();

  try {
    // 1. 데모 사이트 로그인
    await page.goto("https://demo.example.com/login");
    await page.fill("#username", "demo_user");
    await page.fill("#password", "demo_pass");
    await page.click("button[type=submit]");
    await page.waitForSelector("#dashboard", { timeout: 15000 });

    // 2. 다중 필드 폼 작성 (파라미터화된 날짜 포함)
    await page.goto("https://demo.example.com/form");
    await page.fill("#firstName", "Jane");
    await page.fill("#lastName", "Doe");
    await page.fill("#email", "[email protected]");
    await page.fill("#startDate", date);
    await page.selectOption("#country", "KR");
    await page.click("#submitForm");

    // 3. 지연 로딩 콘텐츠 대기
    await page.waitForSelector(".lazy-content", { state: "visible", timeout: 20000 });

    // 4. 스크린샷 + JSON 결과 저장
    const screenshotPath = `${outputDir}/demo-${date}.png`;
    await page.screenshot({ path: screenshotPath, fullPage: true });

    const result = {
      date,
      screenshot: screenshotPath,
      url: page.url(),
      lazyContentLoaded: true,
      timestamp: new Date().toISOString(),
    };
    writeFileSync(`${outputDir}/demo-${date}.json`, JSON.stringify(result, null, 2));

    return result;
  } finally {
    await browser.close();
  }
}

// CLI 실행
if (require.main === module) {
  const date = process.argv[2] ?? new Date().toISOString().slice(0, 10);
  runDemoFlow({ date }).then((r) => console.log(JSON.stringify(r, null, 2)));
}
```

## 5. 실행 및 디버깅

```bash
mkdir -p artifacts
npx ts-node scripts/demo-login-form.ts 2025-06-15
```

실행 중 발생할 수 있는 일반적인 실패와 수정 방법:

- **셀렉터 실패**: `#dashboard`가 없으면 `page.waitForSelector`가 타임아웃됩니다. 실제 DOM을 확인해 `[data-testid=dashboard]` 같은 안정적인 셀렉터로 교체하세요.
- **타이밍 실패**: 지연 로딩 콘텐츠가 늦게 뜨면 `timeout`을 늘리거나 `page.waitForLoadState("networkidle")`를 먼저 호출하세요.
- **폼 제출 후 리다이렉트**: `page.click` 후 `page.waitForNavigation()`을 추가하세요.

수정 후 재실행하여 스크린샷과 JSON이 `artifacts/`에 생성되는지 확인합니다.

## 6. 재사용 가능한 스킬로 정리

`skills/cuawright-web/` 아래에 파라미터화된 스킬을 배치합니다.

```
skills/cuawright-web/
├── SKILL.md
├── run.ts
└── README.md
```

`run.ts`는 위 스크립트에서 `date`, `outputDir`, `headless`를 인자로 받도록 일반화한 버전입니다.

`README.md`:

```markdown
# cuawright-web 스킬

데모 사이트 로그인 → 다중 필드 폼 작성 → 지연 로딩 대기 → 스크린샷/JSON 저장을 수행하는 재사용 스킬입니다.

## 모델 없이 재실행하기

스킬은 결정론적 스크립트이므로 LLM 호출 없이 실행됩니다.

```bash
npx ts-node skills/cuawright-web/run.ts --date 2025-06-15 --out artifacts
```

### 인자
- `--date` (필수): 폼에 입력할 날짜 (YYYY-MM-DD)
- `--out` (선택): 결과 저장 디렉토리, 기본값 `artifacts`
- `--headless` (선택): 기본값 `true`, 디버깅 시 `false`

### 출력
- `artifacts/demo-<date>.png` — 전체 페이지 스크린샷
- `artifacts/demo-<date>.json` — 실행 결과 메타데이터

### 에이전트에서 호출
에이전트는 `skills/cuawright-web/SKILL.md`의 스키마에 따라 `run.ts`를 서브프로세스로 호출하기만 하면 됩니다. 모델 추론 없이 동일한 결과를 재현할 수 있습니다.
```

`SKILL.md`에는 입력 스키마(`date`, `out`, `headless`)와 출력 파일 경로, 실패 시 재시도 정책을 명시해 에이전트가 스킬을 결정론적으로 호출할 수 있도록 합니다.

Source

English

Tools in this stack