메뉴
HN
Hacker News 47일 전

클로드 페이블의 끊임없는 능동적 문제 해결

IMP
8/10
핵심 요약

새로운 AI 모델인 클로드 페이블 5(Claude Fable 5)는 단순한 코드 수정을 넘어 스스로 테스트 환경을 구축하고 브라우저를 조작하는 등 목표 달성을 위해 매우 능동적으로 행동합니다. 이번 사례에서는 가상 환경의 의존성을 분석하는 것에 그치지 않고, 자체적으로 파이썬 스크립트를 이용해 사파리 창을 띄우고 스크린샷을 촬영하는가 하면, HTML 템플릿을 수정해 키보드 이벤트를 발생시켰습니다. 코딩 에이전트의 자율성과 문제 해결 능력이 한 단계 진화했음을 보여주는 중요한 사례입니다.

번역된 본문

사이먼 윌리슨(Simon Willison)의 웹로그 구독 후원: AWS — AI로 무언가를 구축하고 있다면, 6월 17일에 열리는 AWS Summit NYC가 필요한 곳입니다. 200개 이상의 세션이 준비되어 있으며 완전히 무료입니다. 여기서 등록하세요.

클로드 페이블은 끊임없이 능동적입니다 2026년 6월 11일

클로드 페이블 5(Claude Fable 5)를 며칠간 사용해 본 결과, 이를 설명하는 가장 좋은 방법은 '끊임없이 능동적(relentlessly proactive)'이라는 표현인 것 같습니다. 이 모델은 엄청나게 다양한 기법을 알고 있으며, 목표를 달성하기 위해 그중 거의 모든 것을 활용합니다.

하나의 예를 들어 설명해 보겠습니다. 오늘 저는 Datasette Agent를 다루다가 점프 메뉴 채팅 프롬프트에 불필요한 가로 스크롤바가 생기는 버그를 발견했습니다. 저는 스크린샷을 찍었습니다.

그런 다음 datasette-agent 체크아웃 폴더에서 새로운 클로드 세션을 시작하고, 스크린샷을 드래그 앤 드롭한 뒤 다음과 같이 지시했습니다. "여기에 가로 스크롤바가 생기는 이유를 파악하기 위해 dependencies(의존성)를 먼저 살펴보세요."

저는 원인이 Datasette Agent의 의존성(아마도 Datasette 자체)에 있을 것이라는 직감이 들었습니다. 그리고 페이블이 가상 환경의 site-packages에 설치된 파일을 검사하거나 디스크의 로컬 체크아웃을 참조하여 의존성 코드를 파고드는 데 능하다는 것을 알고 있었습니다. 의존성부터 살펴보라고 한 것은 좋은 선택이었습니다.

그 후로 잠시 집안일에 신경을 쓰느라 컴퓨터에서 자리를 비웠습니다. 몇 분 후에 돌아와 보니, 제 컴퓨터가 제가 평소 쓰는 파이어폭스(Firefox)에서 브라우저 창을 열고 문제의 대화 상자로 이동하고 있었습니다. 저는 클로드 코드(Claude Code)에 브라우저 자동화를 사용하라고 지시한 적도 없고, 창 내에서 마우스 움직임이나 키보드 단축키를 트리거할 수 없다고 확신했기 때문에 대체 어떻게 된 일인지 놀랐습니다.

신기하게도 계속해서 탐색하는 것을 지켜보았고, 이번에는 파이어폭스 대신 사파리(Safari) 창을 여는 것을 보았습니다. 저는 클로드 터미널에서 다음 스냅샷도 캡처했습니다.

도대체 uv run --with pyobjc-framework-Quartz 명령어로 무엇을 하고 있었던 걸까요? 알고 보니 페이블이 브라우저 창의 스크린샷을 찍기 위해 자체적인 패턴을 만들어냈던 것입니다. 파이썬(Python)을 사용하여 제 컴퓨터에 있는 사용 가능한 모든 창을 반복(iterate)한 다음, 창 이름에 "textarea"와 같은 예상 문자열이 포함된 사파리 창을 필터링했습니다. 그리고 이를 통해 창 번호(예: 153551과 같은 정수)를 찾아낸 뒤, screencapture CLI 도구를 사용해 PNG 이미지를 캡처한 것입니다.

네, 스크린샷을 찍는 아주 영리한 방법입니다. 하지만 대체 무엇의 스크린샷을 찍고 있었던 걸까요? 알고 보니 버그를 재현하기 위해 자체적인 테스트용 HTML 페이지를 작성한 다음, 사파리를 열고 스크린샷을 찍고 있었습니다. 다음은 이것이 생성한 /tmp/textarea-scrollbar-test.html 페이지와 screencapture -x -o -l 153551 /tmp/safari-cases.png 명령으로 찍은 스크린샷입니다. (저는 열어둔 탭이 너무 많습니다!)

좋습니다. 테스트 페이지를 열고 스크린샷을 찍는 과정은 이해했습니다. 하지만 대체 어떻게 테스트하려던 모달 대화 상자(modal dialog)를 실행시켰을까요? 그것은 클릭이나 키보드 단축키를 통해서만 열 수 있는 기능인데, 사파리에서 이를 실행할 메커니즘이 보이지 않았습니다.

결국 저는 이 에이전트가 무엇을 했는지 알아냈습니다. 클로드는 애플리케이션의 소스 코드가 포함된 폴더에서 실행되고 있었습니다. 이 모델은 Datasette에 대해 충분히 알고 있어서 로컬 개발 서버를 실행할 수 있었습니다. 알고 보니 Datasette의 자체 템플릿을 수정하여 창이 열리자마자 올바른 키보드 단축키를 트리거하는 JavaScript를 추가했던 것입니다. 다음과 같은 코드를 추가했습니다.

창이 열리고 1.2초 후, 이 코드는 모달 대화 상자를 여는 단축키인 '/' 키 누름을 시뮬레이션합니다.

여기서 한 가지 과제가 더 남아있었습니다. 상황을 파악하기 위해 클로드는 페이지에서 직접 JavaScript를 실행하여 측정값을 가져와야 했습니다. 그래서 CORS를 통해 정보를 캡처하는 자체적인 맞춤형 웹 애플리케이션을 작성한 다음, 이를 로컬 서버로 실행하고 그곳에 POST 요청을 보낼 JavaScript가 포함된 페이지를 열었습니다! 다음은 이것이 작성한 파이썬 웹 앱입니다.

원문 보기
원문 보기 (영어)
Simon Willison’s Weblog Subscribe Sponsored by: AWS &mdash; If you&#x27;re building with AI, AWS Summit NYC on June 17 is the room you want to be in. 200+ sessions. Totally free. Register here Claude Fable is relentlessly proactive 11th June 2026 After two days of experience with Claude Fable 5 I think the best way to describe it is relentlessly proactive . It knows a whole lot of tricks and it will deploy pretty much any of them to get to its goal. I’ll illustrate this with an example. I was hacking on Datasette Agent today when I noticed a glitch: a horizontal scrollbar that shouldn’t be there in the jump menu chat prompt. I snapped this screenshot: Then I started a fresh claude session in my datasette-agent checkout, dragged in the screenshot and told it: Look at dependencies to help figure out why there is a horizontal scrollbar here I had a hunch the cause was in a dependency of Datasette Agent (likely Datasette itself) and I knew Fable was good at digging into dependency code, either by inspecting installed files in its own virtual environment site-packages or by referencing a local checkout on disk. Telling it to start with dependencies felt like a good bet. I got distracted by a domestic task and wandered away from my computer. When I came back a few minutes later I saw my machine open a browser window in my regular Firefox and then navigate to the dialog in question . I had not told Claude Code to use any browser automation, and I was pretty sure it wasn’t possible for it to trigger mouse movements or keyboard shortcuts within a window, so how was it doing that? I watched in fascination as it continued with its explorations, then saw it open a Safari window instead of Firefox. I also grabbed this snapshot from the Claude terminal: What was it doing there with uv run --with pyobjc-framework-Quartz ? It turns out Fable had hacked up its own pattern for taking screenshots of browser windows. It was using Python to iterate through all available windows on my machine, then filtering for Safari windows with expected strings such as "textarea" in the window name. It used that to find their window number—an integer like 153551—which it could then use with the screencapture CLI tool to grab a PNG. OK fine, that’s a neat way of taking screenshots. But what was it taking screenshots of? Turns out it had been writing its own scratch HTML pages to try and recreate the bug, then opening Safari and grabbing screenshots. Here’s that /tmp/textarea-scrollbar-test.html page it created, and the screenshot it took with screencapture -x -o -l 153551 /tmp/safari-cases.png : (I have way too many open tabs!) OK, so I can see how it’s opening test pages and taking screenshots, but how on earth was it triggering the modal dialog that was meant to be under test? That’s only available via a click or a keyboard shortcut, and I couldn’t see a mechanism for it to run those in Safari. I eventually figured out what it had done. Claude was running in a folder that contained the source code for the application. It knows enough about Datasette to be able to run a local development server. It turns out it was editing Datasette’s own templates to add JavaScript that would trigger the correct keyboard shortcut as soon as the window opened, adding code like this: < script > window . addEventListener ( "load" , function ( ) { setTimeout ( function ( ) { document . dispatchEvent ( new KeyboardEvent ( "keydown" , { key : "/" , bubbles : true } ) ) ; } , 1200 ) ; } ) ; </ script > 1.2 seconds after the window opens, this code triggers a simulated / key, which is the keyboard shortcut for opening the modal dialog. There was one challenge left. In order to understand what was going on, Claude needed to run JavaScript on the page to take measurements for itself. It wrote its own custom web application to capture information via CORS, then ran that as a local server and opened a page with JavaScript that would POST directly to it! Here’s the Python web app it wrote, using the standard library http.server package: from http . server import HTTPServer , BaseHTTPRequestHandler class H ( BaseHTTPRequestHandler ): def do_POST ( self ): n = int ( self . headers . get ( "Content-Length" , 0 )) open ( "/tmp/diag.json" , "w" ). write ( self . rfile . read ( n ). decode ()) self . send_response ( 200 ) self . send_header ( "Access-Control-Allow-Origin" , "*" ) self . end_headers () def do_OPTIONS ( self ): self . send_response ( 200 ) self . send_header ( "Access-Control-Allow-Origin" , "*" ) self . send_header ( "Access-Control-Allow-Headers" , "*" ) self . end_headers () def log_message ( self , * a ): # quiet pass HTTPServer (( "127.0.0.1" , 9999 ), H ). serve_forever () All this does is accept a POST request full of JSON and write that to the /tmp/diag.json file. It sends Access-Control-Allow-Origin: * headers (including from OPTIONS requests) so that code running on another domain can still communicate back to it. Then Claude injected this code into the template that it was loading in a browser: const host = document . querySelector ( "navigation-search" ) ; const ta = host . shadowRoot . querySelector ( "textarea" ) ; const cs = getComputedStyle ( ta ) ; fetch ( "http://127.0.0.1:9999/diag" , { method : "POST" , body : JSON . stringify ( { dpr : window . devicePixelRatio , scrollWidth : ta . scrollWidth , clientWidth : ta . clientWidth , whiteSpace : cs . whiteSpace , width : cs . width , } ) , } ) ; This took measurements of the <textarea> inside the <navigation-search> Web Component and sent them to the server, which wrote them to a file on disk, which Claude could then read. Having figured out all of these tricks Fable... hit some invisible guardrail and downgraded itself to Opus. Thankfully Opus had access to the full transcript and could continue using the tricks pioneered by Fable, and shortly afterwards found, tested and verified the fix . I prompted Opus to: Write a report in /tmp/automation-report.md where you note down all of the tricks you have used in this session to test against real browsers on my computer, include runnable code examples Which produced this report , which was invaluable for piecing together the details of what had happened for this post. I’ve shared the full terminal transcript of the Claude Code session as well. A review of everything it did Based on a screenshot and a one-line prompt, Claude Fable 5 + Claude Code: Figured out the recipe to run the local development server (with fake environment variables needed to get it running) Fired up a Playwright Chrome session Turned on the visible scrollbars setting for Chrome defaults write com.google.chrome.for.testing AppleShowScrollBars Always (it turned that off again later) Cycled through Firefox and WebKit in Playwright too, failing to recreate the bug Worked out my default browser was Safari Built a textarea-scrollbar-test.html HTML document Opened that in real (not Playwright) Firefox Found that osascript -e 'tell application "System Events" to tell process "firefox" to id of window 1' was blocked because “osascript is not allowed assistive access” Figured out that uv run --with pyobjc-framework-Quartz python workaround, described above Added JavaScript to the site templates in order to trigger the / key Built its own little Python CORS web server to capture JSON data Rewrote the template to capture that data and send it to the server Scripted its way through the Web Component shadow DOM to the information it needed Opened Safari to confirm the source of the bug Modified its custom template to hack in a potential fix Confirmed the hacked fix worked Reported back on how to fix the problem Like I said, relentlessly proactive! I really need to lock this thing down On the one hand, watching Fable go to extreme lengths to get the information that it needed to debug what was, in the end, a two-line CSS fix, was fascinating . But on the other hand... this is a robust reminder that coding agents can do anything you ca