はてなブックマーク新着レポート

会話セッションを邪魔せずに Claude Code / Codex / Cursor を外部イベントで動かすCLIの作り方まとめ

記事の概要

作者が5月ごろから個人で開発しているソース公開サービス「Artifact Share」(AIエージェントが生成したHTMLやMarkdownをURLで共有するサービス)のCLIに、preview というローカルコマンドを追加した話。ブラウザ上で生成ファイルの要素をクリックして指摘を書くと、Claude Code・Codex・Cursor がファイルを修正し、ブラウザが自動リロードで結果を表示するというレビーループを実現している。本記事はその設計判断・実装のまとめ。

全体像:どう動くか

preview <file> を実行すると、そのプロセス自体がローカルサーバーになる。

# 人間側: プレビューを開く(ブラウザが開き、以後は画面上で指摘する)
npx @artifactshare/cli preview ./report.html

# エージェント側: 1周はこの2コマンド
npx @artifactshare/cli preview next --wait 90   # 指摘が届くまで待って受け取る
npx @artifactshare/cli preview done --stdin     # 直した結果を報告する

最大の課題:エージェントを次のターンへ進ませる3つの別解

一番苦労したのはここ。こだわりは「待っている間も会話セッションを邪魔しない」こと。フォアグラウンドで待機コマンドを実行すれば確実だが、待機中はターンが塞がり他の作業を頼めなくなる。その仕組みがエージェントごとに違った。

エージェント使えた仕組み
Claude Codeバックグラウンドタスク完了時の自動ターン再開
Codex実行中セッションへのメッセージのキュー投入
CursorACPで常駐させた専用セッションへの固定プロンプト送信
(共通の保険)「届くまで待つ」コマンドをフォアグラウンドで実行(ターンは塞がる)

Claude Code:バックグラウンドタスクの完了を使う

Bashコマンドをバックグラウンド実行できる標準機能を利用。preview next --wait 3600 をバックグラウンドに仕込んでおくと、バックグラウンドタスク完了時に新しいターンが自動で開く。指摘が届いた瞬間にコマンドが終了し、Claude Code が起きてファイルを直しに行く。修正後は次の待機を仕込み直してループが続く。

Codex:実行中セッションのキューに直接差し込む

Codexにはバックグラウンド完了でターンを再開する仕組みがない(openai/codex#32188)ため別の手段を使う。previewサーバーが起動時にCodexのセッションIDを検出しておき、指摘が届いたらそのセッションへ「届いた」というメッセージをキュー投入。エージェントが指摘を取りに来るまでバッチは消費されず、セッション終了後も codex resume で再開すれば受け取れる。

Cursor:管理下のACPセッションへ固定プロンプトを送る

CursorにはIDEチャットを外部から起こす手段自体がない。使ったのは ACP(Agent Client Protocol)。previewに同梱した専用ランチャーが、ACP経由の専用セッションを1ワークスペースに1つ常駐させ、指摘が届くと「バッチが届いた」という固定プロンプトだけを送信。本文はエージェントが自分で取りに行き、使用中なら通知は保留されバッチは保存されたまま残る。

セキュリティ上の共通設計:通知には指摘の本文もアンカーも乗せず「届いた」という合図だけを運ぶ。中身はエージェントが毎回取りに行く形のため、通知経路が漏れても指摘は流出しない。

設計判断①:常駐デーモンを持たない

設計判断②:指摘の場所を覚える anchor の3種類

type PreviewAnchor =
  | { kind: 'artifact' }
  | { kind: 'text'; state: 'attached' | 'orphaned'; quotedText: string; prefixText: string; suffixText: string; cssPath: string | null }
  | { kind: 'element'; state: 'attached' | 'orphaned'; selector: string; label: string; contextText: string }

設計判断③:指摘は状態を持つ

指摘の状態は draft → requested → in_progress → resolved / dismissed の5つに整理。遷移の主体を固定している:

まとめ・著者の所感