From ac5265be41a56cc0be1e880f02729fce64ac89ce Mon Sep 17 00:00:00 2001 From: Hare Date: Thu, 16 Apr 2026 13:08:08 +0900 Subject: [PATCH] =?UTF-8?q?instruction-file-refs=E5=AE=8C=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO.md | 1 - resources/prompts/common/tool-usage.md | 2 - tickets/instruction-file-refs.md | 184 ------------------------- 3 files changed, 187 deletions(-) delete mode 100644 tickets/instruction-file-refs.md diff --git a/TODO.md b/TODO.md index 698992fb..9c70f4fb 100644 --- a/TODO.md +++ b/TODO.md @@ -5,7 +5,6 @@ - [ ] Compact の改善(要約品質 + 挙動詳細) → [tickets/compact-improvements.md](tickets/compact-improvements.md) - [ ] Protocol の設計 → [tickets/protocol-design.md](tickets/protocol-design.md) - [ ] パーミッション: パターンベースのツール実行制御 → [tickets/permission-extension-point.md](tickets/permission-extension-point.md) -- [ ] instruction のファイル参照化と system prompt の hardcode wrap → [tickets/instruction-file-refs.md](tickets/instruction-file-refs.md) - [ ] ネイティブ GUI クライアント MVP → [tickets/native-gui-mvp.md](tickets/native-gui-mvp.md) - [ ] TUI 拡充 - [ ] Pod の明示的 shutdown → [tickets/tui-pod-shutdown.md](tickets/tui-pod-shutdown.md) diff --git a/resources/prompts/common/tool-usage.md b/resources/prompts/common/tool-usage.md index 1c22ae3b..4263c9e3 100644 --- a/resources/prompts/common/tool-usage.md +++ b/resources/prompts/common/tool-usage.md @@ -1,6 +1,4 @@ ## Tool usage -You have access to these tools: {{ tools | join(", ") }}. - Prefer the most specific tool for the job. When reading files you already know the path of, use the file-read tool directly instead of searching. When searching, use grep/glob primitives rather than shell pipelines. diff --git a/tickets/instruction-file-refs.md b/tickets/instruction-file-refs.md deleted file mode 100644 index 1692946f..00000000 --- a/tickets/instruction-file-refs.md +++ /dev/null @@ -1,184 +0,0 @@ -# instruction のファイル参照化と system prompt 末尾の固定セクション - -## 背景 - -pod-factory で `worker.system_prompt` を minijinja 文字列として扱う形にしたが、その後の運用方針の整理で以下のズレが見えてきた: - -- **manifest を手で触らない前提**なので、`system_prompt` に minijinja 文字列をインラインで書く設計そのものが過剰。人間が書くのはプロンプトの**中身ファイル**だけで十分 -- **AGENTS.md を `files.agents_md` として user template に露出**しているが、ユーザー領域のテンプレートに AGENTS.md 埋め込みを任せると、guard 忘れで静かに消えたり、preset を差し替えるたびに AGENTS.md の扱いが破綻する -- **scope はセキュリティ境界**なので、user の template が覚えていてくれる前提にすべきでない -- **prompt loader が by-name fallthrough**(project → user → builtin を順に探索)になっており、「同名上書き」と「偶然同名」が区別できない曖昧さがある -- 現在バイナリに同梱されている `coder` / `reviewer` / `planner` / `common/tool-usage` は AI 任せで書いた placeholder で、設計者の意図が乗っていない -- 既存の `Scope::summary()` は許可されたパスを列挙するだけで、**`recursive = false` の情報が失われて**おり、非再帰ルールの意味が LLM に伝わらない - -## ゴール - -1. `worker.system_prompt` を**ファイル参照フィールド** (`worker.instruction`) に置き換える -2. `$insomnia` / `$user` / `$workspace` の **import-map 形式の prefix** でプロンプト資産を addressing -3. scope と AGENTS.md を **コード側で system prompt 末尾に付加する固定セクション**として注入し、user template が触れない領域にする -4. 組み込みプロンプトを `$insomnia/default` の 1 本に整理 -5. `Scope::summary()` のフォーマットを改善し、`recursive = false` を明示する - -## 方針 - -### instruction フィールド - -- manifest schema: `worker.system_prompt: Option` を **`worker.instruction: Option`** に置き換える(minijinja 文字列を持つフィールドを消し、ファイル参照だけを受ける) -- 値は import-map 記法のファイル参照: `$insomnia/default` / `$user/my-style` / `$workspace/custom` -- `.md` 拡張子は省略する -- **デフォルト値**は `$insomnia/default`。manifest で `instruction` を書かなければこれが使われる(`defaults.rs` に `DEFAULT_INSTRUCTION: &str = "$insomnia/default"` を追加) -- サブディレクトリ許容: `$insomnia/common/header` は `resources/prompts/common/header.md` を指す - -### Prefix 解決 - -| prefix | 解決先 | -|---|---| -| `$insomnia` | バイナリ同梱の `resources/prompts/`(`include_dir!`) | -| `$user` | `$XDG_CONFIG_HOME/insomnia/prompts/`(factory が設定した user prompts dir) | -| `$workspace` | `/.insomnia/prompts/`(factory が設定した project prompts dir) | - -- 指定した prefix の dir に該当ファイルが無ければ **hard error**(fallthrough しない) -- 現在の「by-name で層を fallthrough して探す」ロジックは撤廃 - -### Unqualified include の相対解決 - -`{% include "name" %}` のように prefix 無しで書かれた場合は、**include を書いたファイル自身の prefix + ディレクトリからの相対**で解決する: - -- `$insomnia/default.md` 内の `{% include "sub" %}` → `$insomnia/sub` -- `$insomnia/common/header.md` 内の `{% include "nested/foo" %}` → `$insomnia/common/nested/foo` -- `$user/custom.md` 内の `{% include "$insomnia/default" %}` → 明示的 prefix が優先 - -これにより「同じディレクトリ内でかたまって動くプロンプト集」を自然に書ける。 - -### system prompt 末尾の固定セクション - -`SystemPromptTemplate` のレンダリング後に、Rust 側で以下の構造を**必ず**付加する(user template からは触れない): - -``` - - ---- -## Working boundaries - -{scope.summary()} -{% if agents_md %} ---- -## Project instructions (AGENTS.md) - -{agents_md 本文} -{% endif %} -``` - -- 付加部分は Rust の `const` またはハードコードされたフォーマット文字列として実装し、`resources/` には置かない(user が触れる場所に置くと、触らないでほしいものが触れる場所に置かれる矛盾になる) -- scope セクションは **必ず** 出力される -- AGENTS.md セクションは不在時に省略(区切り `---` ごと省略) - -### `SystemPromptContext.files` の削除 - -- `files` フィールドごと撤廃(元々 AGENTS.md 専用の予約席) -- user template から AGENTS.md を参照する手段は無くなる(末尾セクションが面倒を見る) - -### `Scope::summary()` フォーマットの改善 - -`crates/manifest/src/scope.rs` の `Scope::summary()` を以下の方針で書き直す: - -- **非再帰ルールを `[non-recursive]` でマークする**。例: - ``` - Readable: - - /home/hare/docs [non-recursive] - Writable: - - /home/hare/Projects/insomnia - ``` -- マーカーの位置はパスの末尾(パースしやすさより人間可読性を優先) -- recursive = true の場合は何も足さない(デフォルトなので無印) -- deny ルールは現行どおり summary には出さない(`from_config` の時点で effective permission に焼き込まれるため) -- `Readable` / `Writable` のセクション分けは現行どおり - -この変更により、最終セクションが出力する scope 情報が LLM にとって正確になる。 - -### 組み込みプロンプトの整理 - -- **削除**: `resources/prompts/coder.md` / `reviewer.md` / `planner.md` / `common/tool-usage.md` -- **新規**: `resources/prompts/default.md` 1 本のみ(内容は本チケットの実装時に author が記述) -- 将来、役割ごとの preset を復活させたくなったら別チケットで追加する(preset 概念そのものが pod-factory の範囲外だった経緯もあり、安易に戻さない) - -## 要件 - -### Schema - -- `manifest::WorkerManifest` と `manifest::WorkerManifestConfig` から `system_prompt` を削除、`instruction: Option` を追加(部分形は Option、resolve 時に `defaults::DEFAULT_INSTRUCTION` で埋める) -- `manifest::defaults` に `DEFAULT_INSTRUCTION: &str = "$insomnia/default"` を追加 - -### Loader - -- `PromptLoader` を prefix addressing 版に書き換える -- API: `PromptLoader::resolve(ref: &str, current: Option<&PromptRef>) -> Result` - - `ref` が `$prefix/path` 形式なら該当 dir を引く - - 素の `name` なら `current` の prefix + dir を前置して再帰 resolve - - `current` が無い状態で素の `name` が来たら **error** -- minijinja の `Environment::set_loader` 内で `current` を追跡する - -### 末尾セクションの組み立て - -- `SystemPromptTemplate::render` 相当の経路で、**user template 出力 + 固定末尾セクション**を連結する -- scope / AGENTS.md を formatter に渡す -- `Pod::ensure_system_prompt_materialized` の既存フローを素直に置き換える - -### `Scope::summary()` - -- `recursive = false` のルールに `[non-recursive]` マーカーを付ける -- 既存の `summary` 形式は維持(`Readable:` / `Writable:` のセクション + インデントのフォーマット) -- `crates/manifest/src/scope.rs` の既存テスト `summary_lists_readable_and_writable` / `summary_excludes_deny_rules` を更新または補完 - -### テスト - -- 既存: `include_resolves_builtin_prompt` / `agents_md_is_injected_when_present` / `files_reserved_namespace_is_empty` / `files_map_*` 系を書き換えまたは削除 -- 新規: - - `instruction_default_resolves_to_insomnia_default` - - `instruction_prefix_addressing_{insomnia,user,workspace}` - - `include_unqualified_resolves_relative_to_current_prefix` - - `include_explicit_prefix_overrides_relative` - - `prefix_with_missing_file_is_hard_error` - - `trailing_section_always_contains_scope_summary` - - `trailing_section_contains_agents_md_when_present` - - `trailing_section_omits_agents_md_when_absent` - - `scope_summary_marks_non_recursive_rules` - -### ドキュメント - -- `docs/pod-factory.md` を更新: - - `files.agents_md` の記述を削除 - - loader の by-name fallthrough 説明を prefix addressing に置き換え - - `instruction` フィールドと `$insomnia/default` デフォルトの記述を追加 - - system prompt 末尾の固定セクション構造を図示 -- 必要なら `docs/system-prompt-template.md` も追随 - -## 他チケットとの関係 - -- **pod-factory (完了済み)**: 本チケットは pod-factory で実装した `PromptLoader` の**一部書き換え**になる。特に「3 層 by-name fallthrough」は撤廃される。pod-factory 自体をロールバックしない -- **tickets/native-gui-mvp.md**: 直接の交差なし。GUI が instruction を差し替えたいときは同じ prefix 形式で渡せば良い -- **tickets/protocol-design.md**: protocol 非依存 -- **tickets/agents-md-ingestion.md (完了済み)**: AGENTS.md 読み取り経路は維持。表面の user template 経路だけが消える - -## 完了条件 - -- manifest `[worker]` から `system_prompt` が消え、`instruction` でファイル参照を渡す形になっている -- `instruction` を省略すれば `$insomnia/default` が使われる -- `$insomnia` / `$user` / `$workspace` の 3 種の prefix でプロンプト資産を参照できる -- prefix 無しの `{% include %}` が include 元ファイルの prefix に相対解決される -- 未知の prefix や不在ファイルは hard error になる -- Pod の system prompt は常に「instruction の render 結果 + scope 要約 + (AGENTS.md があれば)」の構造で組み立てられる -- `SystemPromptContext` から `files` が削除され、user template から AGENTS.md を参照する手段は残っていない -- `Scope::summary()` が `recursive = false` ルールに `[non-recursive]` マーカーを付ける -- `resources/prompts/` は `default.md` 1 本のみ -- 上記挙動がすべて単体テストで担保されている -- `docs/pod-factory.md` が新方針に追随している - -## 範囲外 - -- **preset 概念の復活**: 削除した `coder` / `reviewer` / `planner` を preset として体系化する議論は別チケット -- **instruction をファイル参照以外にする拡張**: インライン minijinja、TOML 配列、等は入れない -- **CLI 変更**: `pod` バイナリの flag は `--overlay` で instruction を上書きできる(`--overlay 'worker.instruction = "$user/foo"'`)形でそのまま使える。新規 flag は追加しない -- **テンプレートエンジンの差し替え**: minijinja を維持 -- **`default.md` 本文の著者判断**: ticket の範囲は枠組み。本文は実装者が書く -- **scope summary に deny ルールを出す改善**: 現行どおり deny は effective permission に焼き込むだけで、summary には出さない