loom-local
Bun をサーバー層として使用し、Claude Code CLI(`claude -p`)をランタイムとするローカル Web アプリケーション構築時に利用します。Bun サーバーが Claude プロセスを起動してブラウザに結果をストリーミング配信します。認証、デプロイメント、マルチテナンシー対応は不要です。以下のような場合に適用されます:「ローカル Claude アプリ」「Claude を使用した Bun サーバー」「claude -p Web アプリ」「ローカル Claude 搭載ツール」「Claude を使用するローカルアプリを構築」、またはブラウザインターフェース経由で Claude のエージェント機能が必要なローカル Web アプリ。デプロイ済みの複数ユーザー対応アプリ(loom を使用)、デスクトップアプリ(loom-desktop を使用)、Anthropic API の直接利用には対応していません。
description の原文を見る
Use when building a local web application that needs Claude Code CLI (`claude -p`) as its runtime, using Bun as the server layer. The Bun server spawns Claude processes and streams results to the browser — no authentication, no deployment, no multi-tenancy. Triggers: "local Claude app", "Bun server with Claude", "claude -p web app", "local Claude-powered tool", "build a local app that uses Claude", or any local web app needing Claude's agentic capabilities through a browser interface. NOT for deployed/multi-user apps (use loom), desktop apps (use loom-desktop), or direct Anthropic API usage.
SKILL.md 本文
Loom Local: Claude Code ランタイム上のアプリケーション (Bun)
Claude Code CLI (claude -p) がランタイムとなるローカルウェブアプリケーションを構築します — React コンポーネントを記述するヘルパーではなく、アプリケーションのインテリジェンスを駆動する実際のエンジンです。インターフェースは claude -p プロセスを起動し、結果をブラウザに ストリーミングする Bun サーバーと通信します。
認証、デプロイ、マルチテナンシーは不要です。ユーザーのマシンには Claude Code が既に認証されており、サーバーはブラウザと CLI の間の橋として機能します。
これが重要な理由
ほとんどの「AI 搭載」ウェブアプリは、チャット API をラップしているだけです。画面にテキストボックスを配置し、メッセージを LLM に送信し、応答を表示します。これはチャットのレプリカにすぎません。
Claude Code はチャット API ではありません。ファイルシステムアクセス、ツール使用、マルチターンセッション、構造化出力、ストリーミングを備えたエージェントランタイムです。その上にインターフェースを構築するということは、これらの機能を公開する何かを設計することを意味します — 単なる会話ではなく、タスクに適した任意のインタラクションパラダイムです。
探求すべき質問: バックエンドがファイルを読み込み、コードを実行し、ウェブを検索し、複数のエージェントを調整し、その推論をリアルタイムでブラウザにストリーミングできる場合、何を構築しますか?
アーキテクチャ
すべてのアプリは同じ基本的な形をしています:
┌──────────────┐ HTTP/WS ┌──────────────┐ stdio ┌──────────────┐
│ Interface │ ◄──────────────► │ Bun Server │ ◄──────────► │ claude -p │
│ (HTML/React)│ │ (Bun.serve()) │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
UI 層 ブリッジ層 ランタイム層
Interface: カスタム UI。構築対象の内容に適切な任意のもの。
Bun Server: ブリッジ。インターフェースからのリクエストを受け取り、Claude プロセスを起動し、出力をパースし、結果をストリーミングして返します。ルーティング、セッション管理、ウェブ概念と Claude 呼び出しの間のマッピングを処理します。
Claude Runtime: インテリジェンス。適切なフラグを付けた claude -p。ファイルを読み込み、コマンドを実行し、構造化出力を生成します。ローカルで実行すると、Claude はマシンの認証情報を自動的に継承します — トークン注入は不要です。
通信パターン
| パターン | 使用場面 | 方法 |
|---|---|---|
| REST + JSON | 単一ショットのリクエスト、データ抽出 | POST → claude -p --output-format json → JSON レスポンス |
| SSE (Server-Sent Events) | ブラウザへのテキストストリーミング | claude -p --output-format stream-json --verbose → SSE ストリーム |
| WebSocket | 双方向、マルチターンセッション | WS 接続 → claude -p --input-format stream-json |
| Background job | 長時間実行タスク | キュー → claude -p プロセス → 結果をポーリング |
| Parallel | 複数アイテムのバッチ分析 | 並行 claude -p 起動 → 結果を集約 |
ほとんどのアプリでは、REST + SSE から開始します: タスク トリガー用 REST、進捗と結果ストリーミング用 SSE。真の双方向通信が必要な場合(例: Claude が動作中にユーザーが割り込むまたはステアリングできる)にのみ WebSocket を追加します。
会話
構築前にこれらの設計質問を検討してください。自然に取り上げてください — すべてを一度にダンプしないでください。
1. ユーザーが何を見て、何をしますか?
AI ではなくインターフェースについて具体化してください。レイアウトは何ですか? 誰が何をクリックしますか? Claude が動作しているときに何が表示されますか? 最終的な出力はどのように見えますか?
質問: 「画面を見ながら説明してください。これを開いたとき、ユーザーは最初に何が見えますか? 最初に何をしますか? 次に何が起こりますか?」
2. インタラクションモデルは何ですか?
ユーザーのアクションが Claude 呼び出しにどのように変換されますか?
| インタラクション | Claude パターン |
|---|---|
| ボタンをクリック、結果を取得 | 単一ショット claude -p、REST レスポンス |
| リアルタイムで進捗を監視 | Stream-JSON → ブラウザへ SSE |
| 状態を持つマルチステップワークフロー | セッションベース(--session-id 最初のターン、--resume <id> その後) |
| 複数アイテムの並行分析 | 並行 claude -p プロセス |
| Claude が動作中にユーザーがステアリング | WebSocket 経由の双方向ストリーミング |
3. Claude は実際に何をしますか?
各アクションを Claude が裏側で必要とするものにマップします:
- どのツール? 読み取り専用分析(
Read,Glob,Grep)対 修正(Write,Edit,Bash)対 ツール なし(--tools ""純粋な推論用) - どのペルソナ?
--system-prompt "You are..."はデフォルトのシステムプロンプトを完全に置き換えます — キャラクターペルソナ、ブランド付きアシスタント、または Claude がユーザーの CLAUDE.md 設定を継承すべきではないアプリ用。--append-system-promptはデフォルトプロンプトに追加します(ユーザー設定、スキルなどを保持) — Claude が一般的なアシスタントとして追加の指示とともに行動すべき場合。 - どのデータ? ディスク上のファイル? ユーザーアップロードのコンテンツ? 他のサービスからのパイプ? Claude の Read ツールはネイティブに画像と PDF を処理します — アップロードされたバイナリファイルを一時ディレクトリに保存し、パスを渡します。
- どの出力形状? 表示用の自由形式テキスト? UI コンポーネント をレンダリングするための構造化 JSON? 両方(構造化には
--json-schema、物語にはresultを使用)?
4. 出力をどのようにレンダリングしますか?
ここが CLI よりもカスタムインターフェースが優れている場所です。Claude の構造化出力をリッチ UI として レンダリングします:
- 型付き配列を持つ JSON スキーマ → カード、リスト、タイムライン、ビジュアライゼーション
- ノードとエッジを持つスキーマ → インタラクティブグラフ
- セクションとステータスを持つスキーマ → プログレスビュー
- Stream-JSON イベント → アニメーション付きプログレスインジケータまたはライブログ
JSON スキーマをレンダリングする UI コンポーネントに合わせて設計します。スキーマは Claude とフロントエンド間の API コントラクトです。
5. セーフティの境界は何ですか?
ローカルアプリはセキュリティを簡略化しますが、排除しません:
- サンドボックス: Claude はファイルシステムアクセスを持っています — 作業ディレクトリをスコープします。 必要に応じて
--add-dirを使用してアクセスを拡張します。 - パーミッション: 機能する最も厳密な
--permission-modeと--allowedToolsを使用します。bypassPermissionsよりdontAskを優先します。 - ターン制限:
--max-turnsを設定して暴走ループを防止します。単一ショット用5、ストリーミング用10-15、マルチターン用20。 - コスト管理:
--max-budget-usdを使用して高コストタスクの支出をキャップします。
6. モデルとパフォーマンス
| ニーズ | フラグ | 理由 |
|---|---|---|
| 高速レスポンス(<3秒) | --model haiku | 分類、抽出、ルーティング |
| 良質で妥当な速度 | --model sonnet | ほとんどのアプリのデフォルト |
| 最高の推論 | --model opus | 複雑な分析、コード生成 |
| 信頼性 | --fallback-model haiku | オーバーロード時の自動フォールバック |
| 推論深度の制御 | --effort high または --effort low | 思考対速度をチューン |
ウェブ UI の場合、認識速度が重要です。ストリーミングを使用して部分的な結果をすぐに表示してください(遅いモデルを使用している場合でも)。
構築方法
サーバー用に Bun と TypeScript、フロントエンド用に HTML/CSS/JS または React をデフォルトにします。外部依存は ゼロです — Bun.serve() は HTTP、静的ファイル、WebSocket をネイティブに処理します。
references/server-patterns.mdで完全なサーバーセットアップ、共有ユーティリティ(cleanEnv()、createStreamParser())、および 5 つのすべての通信パターン実装と完全なコードを読んでください。
セーフティデフォルト
すべてのパターンはサーバーから Claude を実行します — ツール使用を承認するためにターミナルにいるヒューマンはいません。 2 つのフラグは交渉不可です:
--permission-mode dontAsk — クリックする誰もいません。このフラグがない場合、Claude はインタラクティブ入力を待ってずっとハングします。
重要: --permission-mode dontAsk を --allowedTools または --tools とペアリングします。許可されたツールがない場合、dontAsk は Claude にツールをまったく与えません — 推論できますがアクションできず、失敗は無言です(エラーなし、結果が欠けているだけ)。
--max-turns — 機能しないアプローチを Claude が試し続ける会話ループを防止します。
すべてのパターンは 3 つの障害モードも処理します:
- stderr — 警告、エラー、診断。常にキャプチャしてください。
- ゼロ以外の終了コード — モデルオーバーロード、パーミッション拒否、タイムアウト。
- 不正形式の出力 — 強制終了されたプロセスは部分的な JSON を出力する場合があります。常に
JSON.parseを try/catch でラップし、structured_outputを使用する前にis_errorをチェックしてください。
一目でわかるパターン
| パターン | 使用場面 | リファレンス |
|---|---|---|
| REST + JSON | 単一ショットのリクエスト、データ抽出 | references/server-patterns.md#pattern-rest-endpoint |
| SSE ストリーミング | ブラウザへのテキストストリーミング | references/server-patterns.md#pattern-sse-streaming |
| WebSocket | 双方向、マルチターン | references/server-patterns.md#pattern-websocket-session |
| Background Job | 長時間実行タスク | references/server-patterns.md#pattern-background-job-with-progress |
| Parallel | バッチ分析 | references/server-patterns.md#pattern-parallel-analysis |
特定のサーバーエンドポイントを実装するか、フロントエンドを接続する場合は、
references/server-patterns.mdを読んでください。
Stream-JSON イベントタイプ
--output-format stream-json --verbose --include-partial-messages を使用する場合、Claude は改行区切りの JSON イベントを出力します:
| イベントタイプ | 形状 | 転送? |
|---|---|---|
system | {type:"system", subtype:"init", session_id, model, tools} | オプション(session_id を抽出) |
stream_event | {type:"stream_event", event:{delta:{text:"..."}}} | はい(ライブテキスト) |
assistant | {type:"assistant", message:{content:[...]}} | ツール使用のみ(テキストは既にストリーミング済み) |
tool_result | {type:"tool_result", tool_name, content, is_error} | オプション |
result | `{type:"result", subtype:"success" | "error_max_turns", is_error}` |
Max-turns 検出: result イベントは subtype: "error_max_turns" で is_error: false です。 subtype をチェックしてください — is_error が false であるため見落とすのは簡単です。
拡張思考モデル は正しく機能します。思考トークンは delta.text ではなく delta.thinking です — event?.delta?.text チェックは自然にそれらをスキップします。
何を生成するか
アプリを構築するときは、以下を生成します:
server.ts—references/server-patterns.md#server-setupからのBun.serve()ベースラインを使用した Bun サーバー、静的ファイルサービング、エンドポイントパターン、および必要に応じて WebSocket ハンドラ。public/index.html— フロントエンド UI。references/server-patterns.md#frontend-integrationのストリーミングまたは構造化レンダリングパターンを使用します。- 実行する 1 行 —
bun run server.ts— ユーザーがすぐに動作することを確認できるように。
シンプルなアプリの場合、静的 index.html を提供する単一の server.ts が理想的です。複雑な UI の場合、別のサーバーで React フロントエンドをスキャフォルドします。
生成後、サーバーを起動してブラウザで開くことを提案します。次に、ユーザーが見たものに基づいて反復処理します。
最初の実行の信頼性チェックリスト
これらは無言の失敗モードです — エラーメッセージなしで壊れるもの:
- すべてのストリーミング生成で
--include-partial-messagesがオン — これなしでは、テキストは単一ブロックとしてダンプされます - テキストは
stream_eventからのみ転送され、assistantテキストブロックからではない — 別の方法では、すべてのトークンが 2 回表示されます -
cleanEnv()はすべてのBun.spawn/Bun.spawnSyncで呼び出される — これなしでは、Claude Code セッション内で Claude は起動を拒否します -
--permission-mode dontAskは--allowedToolsまたは--toolsとペアリングされている — 許可されたツールなしでは、Claude はエラーなしで空の結果を生成します -
subtype === "error_max_turns"は結果イベントでチェックされている — これはis_error: falseでトリガーされるため、チェックされないと成功に見えます - リクエスト本体は
await req.json()でパースされてからフィールドにアクセス — これなしでは、生成は空のプロンプトを取得します -
stdoutチャンクはパースする前に完全な JSON 行にバッファリングされている — TCP は任意のチャンク境界を配信します
references/cli-runtime-reference.mdで完全なclaude -pフラグリファレンスを読んでください — 入力方法、出力形式、構造化出力、ツール設定、セッション管理、および注意点。
可能性空間
この方法で構築された最も興味深いアプリはブラウザのチャットインターフェースではありません。エージェントランタイムなしでは存在できないもの — バックエンドが従来の API がアクセスできないコンテキストを読み込み、推論し、作用できるアプリケーションです。
質問は「ブラウザにチャットボックスを置くにはどうすればいいですか?」ではなく、「その背後にインテリジェンスがあったら、これはどのようなものに見えますか?」です。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- popmechanic
- リポジトリ
- popmechanic/loom
- ライセンス
- MIT
- 最終更新
- 2026/3/20
Source: https://github.com/popmechanic/loom / ライセンス: MIT