Handbooks
コンセプト

何を信頼できるか

ハンドブックのどの部分がパースされた事実で、どの部分がモデルの出力か。何があなたのマシンを離れるか。そして、このツールが何を拒否するか。

短いまとめ

主張出所間違いうるか?
このファイルはこのパスに存在するパーサーいいえ
この関数は 88–104 行にあるパーサーいいえ
このシグネチャは send(self, url, data)パーサーいいえ
この関数はあの関数を呼ぶパーサーfull ティアではいいえ。generic ティアではベストエフォート
これらの呼び出しは解決できなかったパーサーいいえ — 列挙されるのであって、推測されません
これらのファイルは読めなかった、またはパースできなかったパーサーいいえ — 列挙されるのであって、カバー済みとして数えられません
このファイルはこのステージに属するLLM、機械的に検証判断としては、あり得ます。構造的には、いいえ
このファイルの目的は「…」LLMはい — 文章です
このサブシステムは「…」のように動くLLMはい — 文章です
この状態はこれらのステージを流れるLLM、実在するステージ id 上ではい。ただしステージ id は実在します

設計全体が従うルール: エージェントはこの表の上半分でルーティングし、行動する前に実ソース を読みます。SKILL パッケージは最初の行でそう述べており、そのルーティングプロトコルは 「変更を提案または実施する前に、引用されたすべてのパスで実際のソースを read_file する こと」で終わります。

何があなたのマシンを離れるか

Phase 1 — 何も。 静的解析は完全にローカルです。ネットワーク呼び出しは行われません。

Phase 2 と 3 は、あなたが設定したエンドポイントにソースファイルの内容を送信します。 それは自分のマシンで動くモデル(vLLM、Ollama、LiteLLM)でも構いません。Handbooks には テレメトリもアナリティクスもなく、デフォルトのエンドポイントも OpenAI のもの — キーは あなたが用意します — 以外にはありません。

--max-chars-per-file <n> は、単一ファイルから送信される量の上限を定めます。

レンダリング、パッケージング、検証はネットワークに決して触れません。applyrollback も同様です。

プランナーはソースをローカルで読み、読んだものの抜粋を、生成と同じようにエンドポイント へ送信します。

意図的に拒否されるもの

拒否こそ、このツールの構造を支える部分です。優先順に:

パッチャ

  • アンカーが0 回マッチ → 拒否。コードは先へ進んでいます。
  • アンカーが2 回以上マッチ → 拒否。曖昧です。
  • 「最初のマッチを取る」ことは決してしません。それこそ、パッチが間違った関数に着地する 仕組みです。
  • 1 つの失敗は、1 バイトも書き込まれる前に、適用の全体を中止します。
  • ソースルートを脱出するパス — ファイルがまだ存在しない場合の、シンボリックリンクされた 親ディレクトリ経由を含む — は拒否されます。
  • ロールバックは、パッチの「後」に変更されたファイルを、--force を渡さない限り拒否します。

プランナー

  • 書き込みツールは存在しません。無効化されているのではなく — 実装されていません
  • ## Tool result セクションを捏造する返答は、その末尾にあるどんなプランも含めて丸ごと拒否 されます。そのプランはフィクションから導出されたからです。
  • 諦めたランは、plan.md に謝罪文を書く代わりに、非ゼロで終了します。
  • 破滅的な正規表現((a+)+(.*)*)は、ランをハングさせる前に拒否されます。

パイプライン

  • アナライザが解決できない呼び出しは dropped-calls.json へ行きます。決して推測されません。
  • アナライザが読めない、あるいはパースできないファイルは、理由と共に scan-coverage.json へ行き、scannedFiles からは外されます。空のファイルとして記述されることは決して ありません。部分的にしかパースできなかったファイルは残りますが、それでも列挙されます — その事実は本物ですが不完全であり、どのページがそれに立脚しているかを知っておくべきだから です。
  • カード生成に失敗したファイルは空の説明を得ます。捏造された説明では決してなく、 _coverage.json に列挙されます。
  • ドクターループが提案した構造変更のうち、存在しないステージを名指しするもの、あるいは ファイルを孤児にしてしまうものは、スケルトンに触れる前に拒否されます。
  • 返答がパースできないクリティックは REJECT として数えられます。

設定

  • シークレットは決してコマンドラインフラグにならず、設定ファイルに現れた場合は拒否 されます — 設定ファイルはコミットされるからです。シークレットは 2 つ、llmApiKey / OPENAI_API_KEYllmExtraBody / OPENAI_EXTRA_BODY です。後者は自由形式で、すべての リクエストボディにマージされ、しかもゲートウェイは実際にボディでの認証を受け付けるため、 チューニング用のフィールドと認証情報を見分けられるものが何もありません。
  • llmBaseUrl は意図的に、一律のシークレットではありません。チームがすべてのチェック アウトを 1 つの共有ゲートウェイに向けるのなら、それをコミットする正当な理由があります。 設定ファイルで拒否されるのは、認証情報を埋め込んだ URL(https://user:pass@host/v1) だけです。
  • 与えられたものの不正な値が、デフォルトへこぼれ落ちることはありません。タイポはエラーです。
  • 空の値は未設定として読まれるため、HANDBOOK_TITLE= が無題のハンドブックを生むことは できません。

ドリフトの検出

SKILL パッケージ内の coverage.json は、パッケージング時に取得されたファイルごとの コンテンツハッシュを持ちます。

handbook validate --skill skills/myrepo --source ~/code/myrepo

このコマンドは生きたソースを再ハッシュし、それ以降に内容が動いたすべてのファイルを報告 します。これが、エージェントが古い主張に基づいて行動する前に「このページはコードより遅れて いるかもしれない」と知る方法です — そして、handbook skill--work--source を 渡す価値がある理由です。

訂正チャンネル

ハンドブックの主張が実ソースと矛盾するとき、それを利用するエージェントはスキルルートの corrections.jsonl に 1 行の JSON を追記します:

{
  "file": "src/engine.py",
  "page": "references/stages/stage-2.md",
  "claim": "spin() is defined in src/main.py",
  "actual": "spin() is defined in src/engine.py"
}

handbook resync --corrections <file> は、そこに名指しされたファイルだけを、たとえ バイトが一度も変わっていなくても更新します。ソースが否定する主張は、そのファイルを記述し 直すのに十分な理由だからです。

このファイルはスキルルートに置かれ、references/ の下には決して置かれません。プランナーが あのツリーを読み取り専用でマウントするからです。リビルドは、クリーンをまたいで未処理の 訂正を保持します。

Studio のセキュリティ姿勢

Studio はローカルツールであり、そうでないふりをしません。

  • デフォルトで 127.0.0.1 にバインドします。
  • CSRF ガードはソケットではなく Host リクエストヘッダをチェックするため、ループバック のホスト名だけが通ります。
  • POSTapplication/json を要求します。これが古典的なクロスオリジンフォーム攻撃を 防ぎます。
  • ソースとハンドブックのファイル配信は、登録されたルートにサンドボックスされます。

コンテナ内では、公開ポートに到達可能であるために 0.0.0.0 にバインドしなければなりません が、それで話しかけられる相手が広がるわけではありません: LAN の IP やコンテナのホスト名を 名指しするリクエストは、依然として 403 を受け取ります。リモートアクセスは意図的に未実装 の、独立した機能です — 明示的な許可リストが必要になるでしょう。

Handbook が知っていると主張しないこと

コールグラフは、「なぜ」その決定がなされたのか、プロダクトが何のためにあるのか、チームの 規約が何であるのかを教えてくれません。Handbooks はそれらを推測しませんし、するふりもしま せん。文書化するのは構造と挙動です。意図を書き残すのは、依然としてあなたの仕事です。

このページの内容