- 2日間の実験の結果、Claude Fable 5は「relentlessly proactive」と表現するのが適切だった
- スクリーンショットと1行のプロンプトだけで、ローカル開発サーバーの起動、実際のブラウザー操作、計測コードの挿入まで行い、CSSバグの原因を追跡した
- FableはPlaywright、Firefox、WebKit、Safariを行き来しながらバグの再現を試み、失敗後は実際のブラウザーウィンドウを見つけてスクリーンショット自動化を自ら構築した
/キーで開くモーダルダイアログをテストするため、DatasetteテンプレートにJavaScriptを挿入し、ウィンドウ読み込み後にキーボードイベントを発生させて必要な状態を作り出した
- ページ内部の計測値を得るため、Python
http.serverベースのCORS収集サーバーを作成し、Web Componentのshadow DOM内にある<textarea>情報をJSONとして保存した
- 強力なコーディングエージェントは、ターミナル上でユーザーができることを実行できるため、サンドボックス外で動かすとプロンプトインジェクションやデータ漏えいのリスクが高まる
Claude Fable 5のデバッグ過程
- Datasette Agentのジャンプメニューチャットプロンプトに発生した不要な横スクロールバーの調査を開始
- Claude Fable 5は目標達成のため、さまざまな手法を積極的に動員した
- 入力はスクリーンショットと
Look at dependencies to help figure out why there is a horizontal scrollbar hereという1行のプロンプトだった
- 問題の原因がDatasette Agentの依存関係、とくにDatasette本体にある可能性を見込み、依存コードから調べるよう求めた
- Claude Codeは明示的なブラウザー自動化の指示なしに通常のFirefoxウィンドウを開いてそのダイアログへ移動し、その後Safariウィンドウも開いて探索を続けた
ブラウザースクリーンショット自動化
- Fableは
uv run --with pyobjc-framework-Quartzを使って、ブラウザーウィンドウのスクリーンショットを撮る独自の方法を構築した
- Pythonでマシン上のすべてのウィンドウを走査し、ウィンドウ名に
"textarea"のような想定文字列を含むSafariウィンドウをフィルタリングした
- ウィンドウ番号のような整数識別子
153551を見つけた後、screencapture CLIでPNGを保存した
/tmp/textarea-scrollbar-test.htmlのような一時HTMLページを書き、Safariで開いてスクリーンショットを取得した
- 例のコマンドは
screencapture -x -o -l 153551 /tmp/safari-cases.pngだった
モーダルダイアログの自動実行
- テスト対象のモーダルはクリックまたはキーボードショートカットでしか開けず、Safari内でマウス移動やキーボードショートカットを実行する明確な仕組みは見当たらなかった
- Claudeはアプリケーションのソースコードがあるフォルダーで動作しており、Datasetteのローカル開発サーバーを起動できる程度には構造を把握していた
- DatasetteテンプレートにJavaScriptを追加し、ウィンドウが開いた後に
/キー入力をシミュレートするようにした
- このコードはウィンドウ読み込みから1.2秒後に
/キーのkeydownイベントを発生させ、モーダルダイアログを開くショートカットを実行する
<script>
window.addEventListener("load", function () {
setTimeout(function () {
document.dispatchEvent(new KeyboardEvent("keydown", {key: "/", bubbles: true}));
}, 1200);
});
</script>
ページ内部の計測値収集
- Claudeはページ上でJavaScriptを実行して直接計測値を取得する必要があり、そのためにCORSで情報を受け取る独自のWebアプリケーションを書いた
- Python標準ライブラリの
http.serverを使い、127.0.0.1:9999でローカルサーバーを起動した
- サーバーはJSONを含むPOSTリクエストを受けて
/tmp/diag.jsonに記録し、Access-Control-Allow-Origin: *ヘッダーを返して他ドメインのコードでも通信できるようにした
- Claudeはブラウザーで読み込まれるテンプレートにJavaScriptを挿入し、
<navigation-search> Web Component内の<textarea>を見つけた
- 挿入されたコードは
devicePixelRatio、scrollWidth、clientWidth、whiteSpace、widthを計測してローカルサーバーへ送信する
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,
}),
});
Opusへの切り替えと修正検証
- Fableはいくつもの手法を見つけ出した後、見えないガードレールに引っかかり、Opusへダウングレードされた
- Opusは会話全体の履歴にアクセスでき、Fableが切り開いた手法を引き継いで使用した
- その後Opusは問題を見つけ、テストし、検証したうえで修正コミットを完了した
- Opusはセッション内で実際のブラウザーを対象に使った自動化手法と実行可能なコード例を
/tmp/automation-report.mdにまとめた
- そのレポートは別のgistとして共有され、Claude Codeのターミナル記録全体も公開された
実施した作業の全体レビュー
- Claude Fable 5とClaude Codeはローカル開発サーバーの起動方法を見つけ出し、起動に必要なダミー環境変数も構成した
- Playwright Chromeセッションを起動し、Chromeの可視スクロールバー設定を
defaults write com.google.chrome.for.testing AppleShowScrollBars Alwaysで有効化し、後で再び無効化した
- PlaywrightのFirefoxとWebKitも試したが、バグの再現には失敗した
- 既定のブラウザーがSafariであることを把握し、
textarea-scrollbar-test.htmlというHTML文書を作成した
- 実際のFirefoxでテスト文書を開いたが、
osascriptによるアクセスは「osascript is not allowed assistive access」によってブロックされた
pyobjc-framework-Quartzによる回避策を見つけ、ウィンドウ番号ベースのスクリーンショット取得フローを構築した
- サイトテンプレートにJavaScriptを追加して
/キーを発生させ、PythonのCORSサーバーでJSONデータを受け取った
- Web Componentのshadow DOMをたどって必要な情報を見つけ、Safariでバグの原因を確認した
- ユーザー定義テンプレートに潜在的な修正を適用して動作を確認した後、問題の解決方法を報告した
コスト見積もり
- 利用中のプランは月額100ドルのClaude Maxプランで、Anthropicは6月22日までFableに対して潤沢な利用枠を提供し、その後は通常のAPI料金を請求すると説明している
- AgentsViewは支出追跡に使われ、通常料金で計算した場合、このセッションのコストは約12.11ドルだった
- セッション出力は
68606、最大コンテキストは113178、使用モデルはclaude-fable-5とclaude-opus-4-8だった
- Fableはコストを細かく見ていないと、CSSデバッグのために新しい方法を編み出しながらトークン費用を約12ドルも簡単に消費しうる
サンドボックスの必要性
- Fableが最終的に2行のCSS修正に必要な情報を得るため、極端な方法まで動員した過程は印象的だった
- コーディングエージェントは、ユーザーがターミナルにコマンドを入力して行えることを実行でき、frontier modelは非常に多くの手法を知っている
- 悪意ある指示、コードやissueスレッド内のプロンプトインジェクション、ターミナルに不用意に貼り付けた内容があれば、データ漏えいやその他の被害につながりうる
- サンドボックス外でコーディングエージェントを動かすのは常に悪い考えであり、コーディングエージェントのセキュリティ事故の主要候補とみなされる
- Fableはより賢く、悪意ある指示により疑い深くなれるかもしれないが、ひとたび指示に従ってしまうと、その絶え間ない先回りの能動性によって被害規模が拡大しうる
1件のコメント
Hacker Newsのコメント
これは人間の主体性の致命的な喪失を示す印象的な事例のように読めるし、実際のコミットからもかなり多くのことが見て取れる [0]
作者は横スクロールバーを隠したかった。まともなジュニアのフロントエンド開発者なら、まず「
overflow-x: hidden;をどこに入れる?」と聞くはず。完全な解決には、ブラウザで「Inspect element」を押してCSSクラスを見つけ、コード内で(rip)grepで場所を探して1行追加すればよいもっと主体的なプログラマなら、空のテキストボックスに何のコンテンツが入っていてはみ出しているのか、なぜ根本原因ではなく症状を隠す回避策を2か所に入れなければならないのか、
textareaを一度だけスタイリングしたほうがよくないか、といった質問をしただろう[0] https://github.com/datasette/datasette-agent/commit/a75a8b72...
__init__.pyの中に隠れているのかも尋ねたかもしれない [0]Claudeを使った私の経験では、たいてい構造のしっかりしたコードが出てきたので、実際これは少し驚き。もっとも私は、いわゆる本格的なバイブコーディングというより、ロボットである別のエンジニアと気さくにソクラテス式の議論をしている感覚に近い
[0] https://github.com/datasette/datasette-agent/blob/main/datas...
私がジュニア開発者に期待するのも、まさにそれ。バグが実際に存在するかを確認し、直し方を見つけ、バグが修正されたかを検証すること
問題は、ブログ記事でも的確に指摘されているように、より高い権限が必要なときに止まって尋ねる代わりに、延々と一人でハック的な回避策を探し続ける点にある。人間の開発者で言えば、サードパーティのサンドボックスへのアクセス権が必要なのに、シニアに認証情報を求めず、自分専用のサンドボックスをゼロから作ろうとするようなものだ
以前、オンラインの世界に接続すると分単位で課金されていた時代を思い出す。メーターを回し続けるインセンティブが大きかったが、これもその類ではないかと思う
「コーディングエージェントをサンドボックス外で実行するのは常に悪い考えだった」とはっきり認めながら、それでもそうしている人が多いのは、相変わらず不可解で驚かされる
助手席に座って足をダッシュボードに載せた動画を投稿しながら、「事故に遭ったらエアバッグで脚が折れるか、もっとひどいことになるかもしれないので気をつけてください! 自分にそんなことが起きなくて本当によかったです!」と言っているようなもの
問題は、人によってプロンプトの与え方があまりにも違うことだ。
たとえば私は「この X クラスタ内でこのサービスの k8s pod にこの annotation の複数のバリエーションを試してみて。それで Y 理論を証明できるから」と依頼するかもしれない。ところが同僚は「Y 理論をテストして」と言う。ジュニアエンジニア2人にそう尋ねたら、片方は本番環境で無作為に試し、もう片方はローカルテストを回すかもしれない。「知りたいことは何でもしていいから突き止めろ」という類の 無指示リクエスト であり、エージェントは境界条件は伝えられていないのに「突き止めろ」という圧力だけは強く受けたジュニアのように読んでしまう
claudeにするやり方で満足している。自分の dotfile に近いが秘密情報はない。自分のホームディレクトリは 0700 で、
claudeは別の SSH キーを持ち、自分の GitHub プロフィールに追加してあるがパスワード保護されており、push/pull は自分が代行する。別の Postgres 開発/テスト用ユーザーとデータベースもあり、スーパーユーザーではない。要するに、プロジェクトの他の開発者のように扱っている。sudo で何か実行する必要があれば私に尋ねる。しばしば2人で並行して同じ作業をすることもある。そもそも Unix はマルチユーザーシステムであるはずだった。
よく使うコツは、彼の git リポジトリに次のような追加リモートを置くことだ。
paul ssh://paul@localhost/~/src/example (fetch)paul ssh://paul@localhost/~/src/example (push)まだ共有する準備ができていないものでも共同作業しやすくなる。
この設定はかなり快適だ。ただし Linux の権限昇格バグは心配している。AI が脆弱性の悪用は許されていないと理解しているとは思えない。最初の職場で急ぎの仕事があったとき、公式には
httpd.confの編集に限定された sudo 権限を広げようとして、vim の:!機能を誤用したことを思い出す。今では自動セキュリティアップデートがあっても、手動でより頻繁にパッケージを更新するようになった。Opus がわざわざセキュリティ脆弱性を探すとは思わないが、Fable ならやるかもしれないし、最近はそうした脆弱性が多かった。将来のモデルは自力で新しい脆弱性を見つけたり、SSH キーのパスワードを覚えようとしてキーロガーを仕掛けたりするかもしれない。別ユーザー運用は、別マシンを除けば、私が聞いた中ではほぼ最も偏執的な設定だ。だから、速度と利便性を犠牲にしすぎているのではないかとも思う。それでも実際には依然としてかなり便利で、効率的かつ責任あるやり方だと思っている。穴が見えるなら聞きたい
Fable は「問題が直ったと確信するまで止まれないハーネスの上で動く Opus」のように感じる。ベンチマークでより良いモデルを望むなら筋の通った方向だ。
とても良いモデルだが、プレミアムが大きい。トークン自体が高いだけでなく、モデルがそのトークンを全部使いたがる。たとえば React Native の作業で、Fable は「よし、できた、終わり」とは言わない。アプリ全体を最初から再ビルドし、テストスイート全体を回し、すべてのログと警告を監視しようとする。
LLM を使っていて初めて、会社が許可していてもモデルのアップグレードに価値がないと感じた。ビルドとテストが自分のマシンとバッテリーをあまりに酷使して、ほかの作業ができなくなるからだ。
今は Opus に ultracode を使うほうがよさそうに見える。メインのコンテキスト汚染が少なく、調査もより並列化される
Fable が自分のゲームの UI 変更を検証しようとしていた。私は別ウィンドウで作業していたのだが、タスクバーにプログラムが開くのが見えた。Fable は CLI から movie maker ツール でゲームを起動し、出力を録画し、最後のフレームをキャプチャして UI を検証していた。ゲームのウェルカム画面が見たい部分を隠していたため、一時的な worktree を作ってウェルカム画面を削除し、それから movie maker をもう一度実行した。
その過程を見ながら、ただ自分にスクリーンショットを頼めばトークンを節約できたのにと思った。それでも感心せずにはいられなかった。Opus なら絶対にそんなことはしなかったはずだ
こういう文章は、まるで平行世界から来たように感じる。自分の逸話的な経験と、依然として主観的ではあるが自作したベンチマーク(https://pshirshov.github.io/llm-bench-pi-oneshot/)を見る限り、Fableはそこまで印象的ではない
gpt-5.5やopus 4.8クラスで、良い時もあれば悪い時もあり、明らかにより高価で、Reactの質問に対して「化学なら手伝える」と言って断ることさえある
この騒ぎに本当に根拠があるのか、それともIPO前のAGI誇張なのか分からない
私はFableに複雑な実装の調整をさせている。Linearの親チケットを渡して、「このチケットの子イシューを見て、どれを自分で実装できるか、どの順序で進めるべきか、そして他のチームメンバーが現在作業中の内容とどう調整すべきか判断してくれ」と指示する。これらのチケットは些細なものではなく、可動部分や依存関係が多く、同じプロジェクトの内外、たとえばバックエンドともつながっている
するとFableはチケットを選び、各チケットをサブエージェント(これもFable)に委任する。サブエージェントはそのチケットのFigmaデザインを確認し、リポジトリのガイドラインと慣例を徹底的に守って完璧に実装し、各部分のスクリーンショットを撮り、詳細なコミットメッセージとPR説明を書き、証拠としてスクリーンショットを添付する。最後には「PR #1283が先にマージされる必要があります。なお、あれこれの画面にはFigmaデザインがありませんでしたが、すでに実装されている類似画面を見てパターンを適用しました」といった要約を返してくる
これはおそらくFableができることの20%程度にすぎない。本当に強力なモデルだ
Opus 4.8でもこのうち多くのことはできたが、かなり手取り足取りが必要で、行き詰まる地点に出会うと「ここまではできましたが、これ以上は進められません」と止まる可能性が高かった
Fableは少しだけ賢いが、まさにそのせいで全体としてはより悪いツールのように感じる
1回のプロンプトで終わる50行のパッチを、延々と30分の探索に変えてしまい、それだけの価値がまったくないことが多い。しかも頻繁に間違える
かなり単純な作業で試してみた。ハッシュ関数が変わった時にredisの重複排除キャッシュをバックフィルする仕事だった。すべてのDB値に新しいハッシュ関数をかけてキャッシュを拡張すればよいのに、Fableは各キャッシュ値のハッシュ関数バージョンを推定し、古いハッシュだけを再計算しようとする過剰に複雑なキャッシュ更新を実装した。文脈によっては筋が通るかもしれないが、30分トークンを燃やして出てきた結果は、私が10行のfor loopで置き換えたコードだった
プログラミング全般にとって悪い知らせのように思えて心配だ。LLM技術は知能の面で収穫逓減の壁にぶつかっているようにしか見えず、その対応がただもっと執拗にすることなら、関わる全員にとってひどい解決策だ。トークンを売る人たちと、0-dayをスキャンするためのトークンを負担できる人たちは別だろうが
第一に、因果モデルがない。できるのは試行錯誤の探索だけで、多くの問題にはかなりうまく効くが、他の多くの問題は因果モデルを必要とする
第二に、プロンプトは精密ではない。プログラミング言語と機械モデルは、まさにこの問題を解決するために発明された。英語は素晴らしいが、プログラミング言語ではない
IPOを前に、戦略的な導入と操作をかなり行ってきたし、その点では効果があった
tscを回せばいいだけなのに、各サブエージェントでtscを実行し、その結果をまとめるスクリプトまでまた書いた本当に腹が立つほどだった。長くても1〜2分で終わることが、その経路を通ったせいで10分くらいかかった
後でもっとずっと複雑な作業も試してみるつもりだが、単純なことには郵便受けまでCorvetteで行く感じだった
ローカルマシンでターミナルベースのLLMを使いたくないという拒否感が、引き続き正当化されている気がする
悪意ある行動をしなくても、かなりの作業量を失わせたり、自分のマシンや作業能力そのものを壊したりできることがあまりにも多い
1兆ドル企業なら比較的簡単に用意できるはずではないか。全体のハーネスと比べれば些細なことではないかと思う
セキュリティのほうがより大きな問題なのは確かだが、これを読んでいる間ずっと、CSS 2行を直すためにどれだけトークンを使ったのかということばかり考えていた
人間ならどれだけ時間がかかったかを見積もるべきだ
人々は今や、怠けながら生産的に見せられるようになっただけで、依然として怠けている
メールを1通書くために、数十万ドル相当のハードウェアへのアクセス権が必要な人たちが生まれた。そんなものは御免だ。億万長者の思考マシンに依存するようになるために、自分の脳を焼きたくはない
ローカルの「代わりに考えてくれる機械」であっても、自分の脳を焼くつもりはない。自分がアクセスできるハードウェアより価値のある人間でありたい
Fable 5 が独自のやり方で動いた私個人の体験は非常に良かった
ログやコンソールにエラーを残さない Python モジュールのクラッシュの根本原因を突き止めようとしていた。Fable は UI クリックをシミュレーションするテストハーネスを書いたうえで、私のコードを二分探索して、クラッシュが始まる地点を見つけた。クラッシュ原因について大胆な仮説を立て、その後
/tmp配下にその Python モジュールの各バージョンごとの仮想環境を作る bash のワンライナーを次々に実行し、クラッシュしないバージョンを見つけた私が一人でやったときよりもはるかに深く根本原因を追跡しており、原因はヒープ割り当てオーバーフローを引き起こすモジュールのリグレッションだった。バグレポートを上げるのに十分な情報と単純化した再現例を提示し、私のアプリケーションでそれが起きないようにする回避策も書いた
完全に放任していたわけではない。実行しようとする各 CLI コマンドを私が確認し、「yes」で続行するときは過剰なトークン消費を防ぐために返答を補っていた
プロンプトや Markdown で境界を設定すると役立つ。たとえば Web ブラウザ自動化を使わないように言うと、Fable はそのルールと意図の両方を守っているようだった。妙なハックもしなかった
ただ、一部の単純なデバッグ作業を実際よりも複雑に扱っているようにも見える。元記事はその良い例かもしれない
git bisectループを回すために、本当にエージェントが必要だったのかは疑問テストケースと
git bisectループを生成するところまでは理解できるが、なぜそれをインターネットや GPU などを経由して実行する必要があるのかは分からない。単一コアの Celeron でも動かせる作業ではないかと思う