Handbooks
ガイド

変更の計画

プランナーにリクエストとハンドブックを渡すと、バイト単位で正確な編集プランと、何に触れるかの機械可読な宣言が返ってきます。

handbook plan --source <repo> --handbook <dir> --request "<text>" --out plan.md

プランナーは 読み取り専用 のエージェントです。一覧・読み取り・grep を行います — 書き込みツールは無効化されたものすら一切持ちません — そしてその出力は、別の何かが実行する ためのプランです。

ループ

  1. ハンドブックでルーティングする: どのファイル、関数、状態がスコープに入るか?
  2. 見つけたすべてのアドレスで 実際のソース を読む。
  3. バイト単位で正確な oldnew テキストを持つ ### EDIT n ブロックを出力する。
  4. JSON の宣言ブロックで締めくくる。

2 つの成果物、2 つの役割

ハンドブック はロケーションインデックスです: テキスト検索では見逃す、散在した自明でない箇所 — ミラー実装、ある状態のすべての読み取りと書き込み、サブシステム横断の接点 — を浮かび上がらせます。 実際のソース は、何を変更すべきかについての基準となる真実です。ハンドブックがアドレスを与え、 そのアドレスにあるコードがバイト列を与えます。

良いリクエストの書き方

弱い強い
「アップロードのバグを直して」「503 で失敗したアップロードは、エラーを表面化させる前に指数バックオフで 3 回リトライすべき」
「ログを追加して」「完了したすべての HTTP リクエストについて、既存のロガーを使い、リクエスト ID と所要時間を INFO でログに出す」
「速くして」resolveTenant の結果をテナント ID をキーに 60 秒間キャッシュする」

欲しい振る舞い を述べてください。それがあると思うファイル名ではありません。ファイルを 指名すると、プランナーの探索はあなたがすでに思いついた場所に狭められます — それでは本末転倒 です。

プランの読み方

### EDIT 1

- file: `src/upload.py`
- where: `Uploader.send (~88)` — wrap the request in the retry helper

```old
    response = self._client.put(url, data)
```

```new
    response = self._retry(lambda: self._client.put(url, data), attempts=3)
```

### EDIT 2

- file: `src/upload.py`
- where: `Uploader` — add the helper

```old
    def send(self, url, data):
```

```new
    def _retry(self, call, attempts):
        last = None
        for _ in range(attempts):
            try:
                return call()
            except TransientError as exc:
                last = exc
        raise last

    def send(self, url, data):
```

Both call sites now share one retry policy.

```json
{ "will_modify": ["Uploader.send"], "will_add": ["Uploader._retry"], "will_remove": [] }
```

このフォーマットが従うルール:

  • oldバイト単位で正確 に、ファイル内に ちょうど 1 回 現れなければなりません。
  • old は「このファイルを作成する」を意味します。
  • 編集は番号付きで、上から下へ 昇順 に並びます。
  • 末尾の json ブロックは resync に消費され、リフレッシュ範囲を絞り込むのに使われます。

適用する前にプランを読んでください。 ドライランが教えてくれるのは適用 できる か どうかです。適用 すべき かどうかを判断できるのはあなただけです。

諦めたとき

plan非ゼロで終了します — スクリプトが apply に流し込んでしまうような謝罪文を plan.md に書き込んだりはしません。

aborted何が起きたかどうするか
fabrication応答が ## Tool result セクションを 3 回捏造した — 想像上のファイル内容の上で推論していたより強いモデルを使ってください。その実行から得られたものは何も信頼できません
turn-limitEDIT ブロックがないままターンを使い切った--max-turns を上げるか、リクエストを絞ってください
no-plan使えるものが何もないまま finish を呼んだたいていはコード変更を必要としないリクエストか、局所化するには曖昧すぎるリクエストです

なぜ捏造は即座に拒否されるのか

観測されたある応答には、13 個の捏造されたツール結果と、ファイルに存在しない行から組み立てられたプランが 含まれていました。プランナーはその応答を丸ごと拒否します — 末尾のプランも含めてです。 そのプランはフィクションから導かれたものだからです。

チューニング

フラグデフォルトいつ変えるか
--max-turns <n>30大きなリポジトリや広範な変更では上げ、コストを抑えたいときは下げます
--model <id>gpt-4o-miniより強いモデルの恩恵を最も受けるのがこのコマンドです
--handbook <dir>常に渡してください。これがないとプランナーは手探りで探索します
--out <file>(stdout)パイプするときは省略します

ハンドブックなしの場合

handbook plan --source ~/code/api --request "…"

動作はします — プランナーはソースを直接探索するモードにフォールバックします — が、これは 劣化モードです。ハンドブックが存在するのはまさに、ガイドなしの探索は自明な箇所を見つけて 散在した箇所を見逃すからです。

サンドボックスが許可すること

list_dir(path)
read_file(path, start_line?, end_line?)
grep(pattern, path)
finish(plan)
  • すべてのパスはサンドボックスルートの内側で解決されます。シンボリックリンク経由を含め、 外への脱出は拒否されます。
  • ハンドブックは __handbook__/ に読み取り専用でマウントされます。これはソースとは 別個の サンドボックスです。
  • 読み取りは 60,000 文字が上限、grep は 100 ヒットが上限で、5 MB を超えるファイルは スキップされます。
  • 破滅的な正規表現 — (a+)+(.*)* のような、量指定子を含むグループへの無制限の 量指定子 — は、実行をハングさせる代わりに、穏当なツールエラーとして拒否されます。

次へ

このページの内容