← すべての記事

Clawの解剖学:オーケストレーション層としての84のHook

最初のHookを書くのに4分かかりました。Anthropic専用のワークフローでモデルがOpenAI製品を提案するのをブロックするためのものでした。2ヶ月後、その1つのHookは84になっていました。84のHookは43のSkill、19の特化型エージェント、30のライブラリモジュールと接続されていました。ある時点で、このコレクションはスクリプトの集合であることをやめ、オーケストレーション層になっていました。

そうなるように設計したわけではありません。「15,000行のエージェントインフラを構築しよう」と座って決める人はいません。1つの問題を解決します。次にもう1つ。そして、問題同士が干渉し合う問題を解決します。アーキテクチャに気づいた頃には、それはすでに存在しています。

Andrej Karpathyも気づいていました。2026年2月、彼は「Claws」を新しい計算層として説明しました。LLMエージェントの上に構築されるオーケストレーション、スケジューリング、コンテキスト管理、ツールルーティングの層であり、エージェントがLLMの上に構築されるのと同じ構造です。1 この枠組みは、実践者たちが名前をつけずに構築してきたものを明確に結晶化させました。この記事は、そのようなシステムの1つの解剖学です。何が含まれているか、どのように成長したか、どこで機能し、どこで失敗するかを記します。

TL;DR

Karpathyの「Claws」層は、エージェントCLIの上に構築されたオーケストレーションシステムを説明するものです。私はClaude Code上で2ヶ月かけて自然発生的にこのシステムを構築しました。15のイベントタイプにまたがる84のHook、43のSkill、19のエージェント、30以上のライブラリモジュールで構成されています。このシステムはClawsの5つの機能(オーケストレーション、スケジューリング、コンテキスト管理、ツールルーティング、品質保証)にきれいにマッピングでき、1つの注目すべきギャップ(宣言的ワークフロー定義)があります。主要な発見として、計画と実行の分離がHookベースのオーケストレーションの自然な性質として浮上しました。設計目標としてではなく。Lattnerの「判断と抽象化がコアであり続け、AIが実装を自動化する」という観察は、Hookアーキテクチャに直接対応します。ガバナンスHookが判断を行使し、自動化Hookが実装を実行します。


Clawsの分類体系

Karpathyの説明では、Claws層が果たす5つの機能を特定しています。各機能には、過去2ヶ月間にClaude Code上で構築したHookシステムに直接対応するものがあります。1

Clawsの機能 説明 実装
オーケストレーション 複数のエージェントを目標に向けて調整 Ralph自律ループ審議システム
スケジューリング タスクの実行タイミングを決定 CronのHook、activity-heartbeat.sh、夜間セキュリティスキャン
コンテキスト管理 ターン間で関連情報を維持 プロンプトディスパッチャー、フィロソフィーインジェクター、メモリカプセル
ツールルーティング ツールコールを適切なハンドラーに振り分け PreToolUse、PostToolUse、UserPromptSubmitイベントにまたがる84のHook
品質保証 出力が基準を満たしているか検証 品質ゲート、エビデンス要件、7つのレビューエージェント

この分類体系が有用なのは、実践者が絡み合った形で構築しがちな関心事を分離するためです。初期のHookはコンテキスト管理と品質保証を混在させていました。コスト追跡Hookは予算コンテキストの注入(コンテキスト管理)と高額な操作のブロック(品質保証)の両方を行っていました。これらを別々のHookに分離したことで、各Hookが他の機能を壊すことなく独立して失敗できるようになり、信頼性が向上しました。


システムの全体像

2026年2月時点の数値です。

コンポーネント 用途
Hook 84 15のHookイベントタイプにまたがるイベント駆動関数
Skill 43 名前で呼び出される再利用可能な機能モジュール
エージェント 19 レビュー、探索、開発のための特化型サブエージェント
ライブラリモジュール 30以上 PythonとBashの共有ユーティリティ
コード行数 約15,000 Hook、Skill、エージェント、ライブラリ、設定ファイル全体

イベントタイプごとのHook分布は、オーケストレーションの複雑さがどこに集中しているかを示しています。

イベントタイプ Hook数
UserPromptSubmit 9(ディスパッチャー経由) コンテキスト注入、コスト追跡、使用状況分析
PreToolUse:Bash 12 セキュリティスキャン、認証情報チェック、機密コマンドのブロック
PostToolUse:Bash 6 出力スキャン、デプロイ検証
PreToolUse:Write 4 認証情報の検出、パス検証
PreToolUse:Edit 3 パターンの強制
PreToolUse:Task 3 再帰ガード、スポーン予算管理
PreCompact 1 メモリカプセル、デススパイラル検出
SessionStart 1 環境の初期化
WorktreeCreate 1 分離ブランチの環境セットアップ
WorktreeRemove 1 クリーンアップ前の安全チェック
その他のイベントタイプ 約43 PreToolUse:Read、PostToolUse:Write、PreToolUse:WebFetch、NotebookEdit、および8つの追加イベントタイプに分散

UserPromptSubmitが最も負荷が大きいのは、すべてのユーザーメッセージで発火するためです。ディスパッチャー(prompt-dispatcher.sh)は、すべてのプロンプトに対して9つのHookを順次実行します。セキュリティフィルタリング、アナリティクス、使用状況追跡、システム監視、目標注入、時間見積もりブロック、コンテキスト注入、メモリトピック注入、コンテキスト圧力監視です。2

各Hookはレイテンシを追加します。9つの逐次Hookで、プロンプトあたり合計200msの測定値が加わります。ディスパッチャーがこれらを(並列ではなく)逐次実行するのは、初期のテストで共有JSON状態ファイルへの同時Hook書き込みがデータ破損を引き起こしたためです。2つのHookがjiro.state.jsonに同時に書き込むと、切り詰められたJSONが生成され、すべての下流Hookが壊れました。逐次実行は遅いですが安全です。200msのオーバーヘッドはユーザーにとって不可視です。人間のタイピング速度がボトルネックであり、Hookのレイテンシではないためです。


成長の過程

成長は線形ではありませんでした。問題→解決→統合のサイクルパターンに従いました。

フェーズ1:単一目的のHook(1〜2週目)。 各Hookが1つの問題を解決しました。enforce-opus-model.shはOpus以外のモデルリクエストをブロックしました。no-time-estimates.shはレスポンスから工数見積もりを除去しました。filter-sensitive.shはツールコール内の認証情報を検出しました。これらのHookは独立して動作していました。どのHookも他のHookの存在を知りませんでした。

フェーズ2:調整の問題(3〜4週目)。 Hookが互いに干渉し始めました。認証情報フィルターが正当なAPI呼び出しをブロックしました。モデルエンフォーサーがサブエージェントのスポーンと競合しました。解決策はディスパッチャーでした。単一のエントリーポイント(prompt-dispatcher.sh)が7つの個別UserPromptSubmit Hookを置き換え、実行順序を制御し、キャッシュされたstdinパイプを通じて状態を共有するようになりました。

フェーズ3:複合機能(5〜8週目)。 個別のHookがシステムに組み合わさりました。品質ループは、pre-tool Hook(問題が発生する前に検出)とpost-tool Hook(発生後に結果を検証)を共有状態ファイル(jiro.state.json)を介して接続しました。審議システムは、再帰ガード、スポーン予算、合意プロトコルを使用して、無限ループなしに複数のエージェントを調整しました。Ralph(自律開発ループ)は、PRDファイルからClaudeスポーン、テスト検証、コードレビューまでを1つのオーケストレーションされたパイプラインで接続しました。

フェーズ4:自己認識(9週目以降)。 システムは、自身を理解するためのツールが必要なほど大きくなりました。Hookシステム全体のセマンティック検索(/find Skill)により、エージェントはファイル名ではなく目的でHookを発見できるようになりました。パフォーマンス監視(/perf Skill)は、システム自体のオーバーヘッドがマシンを劣化させていないかを追跡しました。コンテキスト圧力モニターは、オーケストレーション層が注入するコンテキストがモデルのコンテキストウィンドウを過剰に消費している場合に警告を発しました。

単一目的のHookから自己監視インフラへの進行は、Chris LattnerがClaude C Compilerプロジェクトのレビューで特定したパターンと一致しています。「優れたソフトウェアは判断力、コミュニケーション、明確な抽象化に依存する。AIはこれを増幅させた。」3 Hookシステムのアーキテクチャは同じ真実を明らかにしています。価値のあるHookは、タスクを自動化するものではありません。価値のあるHookは、タスクがいつ、どのように自動化されるべきかについての判断をエンコードするものです。


判断Hook vs. 自動化Hook

LattnerのClaude C Compilerレビューは、AIがうまく自動化するもの(実装)と、根本的に人間に残るもの(判断と抽象化)を区別しました。3 この区別はHookシステムに直接対応します。

判断Hookは、何かが起こるべきかどうかを決定します。手順ではなく、ポリシーをエンコードします。

Hook 判断内容
quality-gate.sh 「この作業は報告するのに十分な完成度か?」
filter-sensitive.sh 「このコマンドは認証情報を漏洩するリスクがあるか?」
recursion-guard.sh 「エージェントはサブエージェントを生成しすぎていないか?」
context-pressure.sh 「コンテキストウィンドウが一杯すぎて効果的に継続できないか?」
cost-gate.sh 「このセッションは予算閾値を超えたか?」

自動化Hookは、あらかじめ決められたアクションを実行します。ポリシーではなく、手順をエンコードします。

Hook 自動化内容
inject-context.sh 日付、時刻、作業ディレクトリ、ブランチをすべてのプロンプトに注入
track-usage.sh トークン数とセッションメトリクスを記録
sysmon-snapshot.sh CPU、メモリ、ディスクの状態を取得
memory-capsule-inject.sh コンパクション後にコンテキストを復元
activity-heartbeat.sh セッションの生存インジケーターを更新

判断Hookは書くのが難しく、テストも難しく、そしてより価値があります。quality-gate.shは7つの名前付き失敗モード、6つのエビデンス基準、曖昧表現検出器を必要としました。inject-context.shは5行のbashで済みました。しかし両方とも必要です。自動化Hookは判断Hookが評価するデータを提供します。sysmon-snapshot.sh(自動化)はデータをパフォーマンスモニターに供給し、そのモニターがエージェント数のスロットリングを推奨するかどうかを決定します(判断)。

比率が重要です。健全なオーケストレーション層では、判断Hookが自動化Hookを上回るべきです。ほとんどのHookがデータ注入やメトリクス記録だけであれば、システムはうまく自動化しますが、ガバナンスは不十分です。現在のシステムの検証済み数値:判断Hook 35、自動化Hook 44、おおよそ4:5です。自動化がまだリードしています。比率は約1:6(ほぼすべてが注入とロギングのHook)からスタートし、純粋な自動化では防げなかった障害に遭遇した後にガバナンス制約が追加されるにつれて、2ヶ月かけて判断側にシフトしました。比率はまだ均衡に達していませんが、それ自体が有用なシグナルです。このシステムは、自動化するほどにはまだガバナンスしていません。


計画と実行の分離

Boris Taneの「How I use Claude Code」という記事は、Hacker Newsで936ポイントを獲得しました。ワークフローパターンとして、計画と実行の分離を説明したものです。4 1つのClaudeセッションで計画し(調査、アウトライン作成、設計)、計画を構造化された入力として受け取る新しいセッションで実行します。このパターンが共感を呼んだのは、現実の問題を解決するためです。計画と実行はコンテキストウィンドウのスペースを奪い合います。

Hookシステムは別の経路で同じ分離に到達しました。審議システムは、アプローチを調査・議論するために特化型エージェントをスポーンします。出力は、ストーリー、受け入れ基準、検証タイプを含む構造化されたPRD(プロダクト要件定義書)です。RalphループはPRDを読み取り、各ストーリーを実装するために新しいClaudeインスタンスをスポーンします。計画エージェントは決して実装しません。実装エージェントは決して計画しません。

この分離は設計目標ではありませんでした。2つの独立した制約から生まれました。

  1. コンテキストウィンドウの圧力。 計画には多くのファイルを読み、選択肢を探索する必要があります。実装には現在のタスクに集中したコンテキストが必要です。両方を同じコンテキストウィンドウに入れると、どちらも十分なスペースを得られません。セッションを分離することで、各フェーズがフルコンテキストを利用できます。

  2. 品質検証の独立性。 同じエージェントが計画と実装を行うと、計画に対する自身の実装を客観的に検証できません。計画とコードだけを持つ新しいエージェントが独立した検証を提供します。Ralphループはこれを強制しています。実装エージェントがテストを実行しますが、3つの別々のレビューエージェント(正確性、セキュリティ、規約)が結果を検証します。

Taneの手動ワークフローと自動化されたHookシステムの間の収束は、計画と実行の分離が単なる実践者の好みではなく、エージェントシステムの自然な性質であることを示唆しています。コンテキストウィンドウを管理し、出力を検証するシステムは、最終的に計画と実行を分離します。なぜなら、両方を1つのコンテキストで行う代替案は、両方のフェーズでより悪い結果を生むからです。


Hookシステムの限界

このアーキテクチャには、専用のオーケストレーションフレームワークであれば解決できる3つの重大な弱点があります。

宣言的ワークフロー定義がありません。 すべてのワークフローがbashスクリプトに命令的にエンコードされています。Ralphループは1,320行のbashで、特定のシーケンスをエンコードしています。PRDの読み取り、ストーリーの選択、コンテキストの収集、Claudeのスポーン、テストの実行、レビューの実行、失敗の処理、状態の更新です。ワークフローを変更するにはbashを編集する必要があります。宣言的システムであれば、ワークフローをインタープリターが実行するデータ(YAML、JSON)として定義できます。宣言的ワークフローは変更、合成、可視化が容易です。命令的スクリプトは最初は書きやすいですが、成長するにつれて保守が困難になります。

Hookの順序が脆弱です。 プロンプトディスパッチャーはHookをハードコードされた順序で実行します。memory-capsule-inject.shinject-context.shの前に移動すると、カプセルインジェクションが壊れます。inject-context.shが解決するセッションIDに依存しているためです。これらの依存関係は暗黙的(ディスパッチャーの順序でエンコード)であり、明示的(Hook間の依存関係として宣言)ではありません。専用システムであれば、Hookの依存関係をDAGとして表現し、実行順序をトポロジカルソートで決定できます。

ワークフローの可視化がありません。 84のHookがある状態で、ユーザーアクションの完全な実行パスを理解するには、ディスパッチャーのコードを読み、Hookチェーンを手動でトレースする必要があります。「ユーザーがメッセージを入力すると、これらの9つのHookがこの順序で発火し、Hook 3がライブラリ関数Xを呼び出し、状態ファイルYに書き込む」と表示するツールがありません。システムはログを通じて観測可能ですが、構造を通じてではありません。専用のオーケストレーションフレームワークであれば、Hookの依存関係、データフロー、実行パスの視覚的なグラフを提供できます。

これらの弱点には共通の原因があります。このシステムは、一貫したオーケストレーション層として設計されたのではなく、個別の問題を解決することから有機的に成長したということです。有機的成長は、動作するシステム(84のHookすべてがプロダクションで正しく機能)を生み出しますが、全体として推論するのが困難です。このトレードオフは現実のものです。オーケストレーション層を事前に設計していれば、より良い構造が得られたでしょうが、より劣った機能になっていたでしょう。多くの機能(メモリカプセル、出力ホワイトリスト、スポーン予算)は、発生前に予測できなかった障害に対応して発明されたものだからです。


実践者が持ち帰るべきこと

エージェントCLIの上にオーケストレーション層を構築している場合、このシステムから3つのパターンが直接移植できます。

個別のHookではなく、ディスパッチャーから始めてください。 最大のアーキテクチャ改善は、7つの個別UserPromptSubmit Hookを1つのディスパッチャーに置き換えたことでした。任意のイベントタイプで3つ以上のHookを想定する場合、最初にディスパッチャーを構築してください。ディスパッチャーの作成に費やす30分が、後のHook相互作用バグのデバッグに費やす数時間を節約します。最小パターンは以下の通りです。

#!/bin/bash
# dispatcher.sh — sequential hook execution with shared stdin
HANDLERS=("inject-context.sh" "track-usage.sh" "quality-gate.sh")
HOOK_DIR="$(dirname "$0")/handlers"
INPUT=$(cat)  # Cache stdin once (each handler gets the same input)

for handler in "${HANDLERS[@]}"; do
    [ -x "$HOOK_DIR/$handler" ] && echo "$INPUT" | "$HOOK_DIR/$handler"
done

この単一のディスパッチャーをHookのエントリーポイントとして登録します。構築するにつれてハンドラーを配列に追加します。各ハンドラーは同じキャッシュされたstdin(Hookイベントペイロード)を読み取り、独立してstdoutに書き込みます。

判断と自動化を早期に分離してください。 新しいHookを書くとき、「このHookは何かが起こるべきかを判定するのか、それともあらかじめ決められたアクションを実行するのか?」と問いかけてください。判断Hookはより多くのテスト、より多くのエッジケース処理、より多くの反復が必要です。自動化Hookは信頼性とパフォーマンスが必要です。両者を同じように扱うと、テスト不足の判断Hookと過剰設計の自動化Hookが生まれます。

計画と実行の分離は自然に生まれるのを待ってください。 初日から分離を強制しないでください。動作する最もシンプルなものを構築してください。エージェントのコンテキストウィンドウが計画と実装の両方に対して一杯すぎることに気づいたら、分割してください。エージェントが自身の作業を客観的に検証できないことに気づいたら、独立したレビューエージェントを追加してください。制約が要求するとき、分離は自明に感じられるでしょう。

Hookベースのアプローチには、専用のオーケストレーションフレームワークに対する1つの利点があります。コミットメントがゼロであることです。すべてのHookは独立しています。1つのHook、10のHook、または84のHookを採用できます。(ディスパッチャーを維持する限り)他を壊すことなく任意のHookを削除できます。学ぶべきフレームワークも、管理すべき依存関係も、運用すべきランタイムもありません。オーケストレーション層は、ただのファイルです。

Karpathyはこれを新しい計算層と呼びました。実装は名前よりも古くから存在しています。実践者たちは、エージェントCLI呼び出しをラップするシェルスクリプトを初めて書いた時からClawsを構築してきました。シェルスクリプトとオーケストレーション層の違いは、種類の違いではありません。解決した問題の数と、それらの解決策が互いを解決しなければならなかった回数の違いです。


出典


  1. Andrej Karpathy、「Claws」に関する議論、2026年2月、x.com/karpathy/status/2024987174077432126。Simon Willison経由、simonwillison.net/2026/Feb/21/claws/。 

  2. コンテキスト注入アーキテクチャの詳細は「Context Is Architecture」を参照。 

  3. Chris Lattner、「The Claude C Compiler: What It Reveals About the Future of Software」、Modularブログ、2026年2月。Simon Willison経由、simonwillison.net/2026/Feb/22/ccc/。 

  4. Boris Tane、「How I use Claude Code」、boristane.com、2026年2月。Hacker Newsで936ポイント、569コメント。