spec 1.0 · 規範
ブートプロファイル
ブートプロファイルは、コンテキストレイヤーに設ける、エージェントに依存しないエントリポイントです。すべてのエージェントホストと人が共通の起点として使える、人が読める単一の文書です。「このコンテキストレイヤーは何か」「何を読み込むのか」「ここでどう振る舞うのか」に答えます。
要件#
-
コンテキストレイヤーは、マニフェストの
bootProfilePathが宣言するパスに、ちょうど 1 つのブートプロファイルを持たなければなりません(MUST)。推奨される既定値はdocs/boot-profile.mdです。 -
ブートプロファイルは、ツールなしで人が読める素の markdown でなければなりません(MUST)。いかなるベンダーの設定構文にも依存してはなりません(MUST NOT)。
-
ブートプロファイルは、次を扱わなければなりません(MUST)。
- Identity(概要):このリポジトリまたは製品が何であるかを、1 段落で記述します。
- Loading(読み込み):どの種類の作業で、どのコンテキストを読むか。まず無条件の集合(どの作業の前にも読むもの)を示し、続いて、パス、カテゴリ、またはコンテキストインデックスによって経路を決める作業種別ごとのセレクタと、どのセレクタにも当てはまらない作業向けに定義されたフォールバックを示さなければなりません(MUST)。これは、Task routing のアルゴリズム(machine-readable-surface.md)を、実際の作業で使う言葉によってブートプロファイルの水準で表したものです。従うために、そのアルゴリズムの知識は必要ありません。
- Posture(姿勢):エージェントに期待する運用上の振る舞い(いつ進めてよいか、いつ質問するか、決してしてはならないこと)。これは、ガバナンスの内容や core のエージェントプロファイルへの参照として持たせても構いません(MAY)。
-
ブートプロファイルは、マニフェスト、インデックス(あれば)、エージェントプロファイル(あれば)へリンクすべきです(SHOULD)。どのホストから入ったエージェントでも、機械可読なサーフェス全体を見つけられるようにするためです。
-
ブートプロファイルは、実際の作業で使う言葉で記述しなければなりません(MUST)。実際のパスと具体的な読み込み順を明示し、それに従うためにこの仕様の知識を必要としないようにします。マニフェストとスキーマはツールのためのものであり、エージェントのためのものではありません。従うために仕様の理解が必要なブートプロファイルは、適合性に問題がある可能性を示します。
-
ブートプロファイルは、コンテキストレイヤーを保守する責務として、変更の記録先(宣言された変更履歴)と、決定の残し方(宣言された決定記録の場所)を記述すべきです(SHOULD)。ブートプロファイルがいずれにも触れていない場合、バリデーターは警告します。
-
ベンダーのエントリポイントファイルは、context-layer.md のベンダーアダプタの規則に従ってブートプロファイルへ誘導します。
-
ブートプロファイルの無条件の読み込み集合(どの作業の前にも読むと述べているもの)は、すべての作業が必要とするものに限るべきです(SHOULD)。一部の作業しか必要としないコンテキストは、あらかじめ読み込むのではなく、作業、カテゴリ、インデックスによって経路を決めるべきです(SHOULD)。また決定記録は、際限なく積み上がるので、ディレクトリごと読み込むのではなく、宣言された
affectedPaths/affectedCategoriesによって経路を決めるべきです(SHOULD)。無条件の集合にあるものは、毎回の作業でその読み込みコストを負担することになります。 -
フェデレーションされた兄弟。
federation.mountsを宣言するコンテキストレイヤー(distribution.md に従うもの)は、それらの兄弟を、機械が確認できる形でブートプロファイルに示さなければなりません(MUST)。info 文字列がleji-mountsであるフェンス付きブロックを 1 つ以上、文書のどこに置いてもよく、その各エントリは文書の順に連結され、宣言された各マウントにつきちょうど 1 エントリを持ちます。エントリは、その兄弟、所有者、それが何を運ぶか、いつ読むかを名指しします。後ろの 2 つは書き手の作業の言葉で書きます。実際の例は要件のあとにあります。すべての実装が同一に読めるよう、文法は固定されています。ブロックは、3 つ以上のバッククォートに続けて info 文字列を書いた行で開き、次の 3 つ以上のバッククォートの行で閉じます。閉じフェンスのバッククォートの数が開きフェンスと一致している必要はありません。info 文字列は
leji-mounts単独です。その後にトークンを持つフェンスはエラーであって、無視されるフェンスではありません。フェンスの行はスペースまたはタブの字下げや前後の空白を持っても構いませんが(MAY)、その間のレコードは持ってはなりません(MUST NOT)。レコードは 1 桁目の- mount:で始まり、そのフィールドはちょうど 2 つの ASCII スペースで字下げされます。ひとつのレコードの中でowner、carries、read-whenはそれぞれちょうど一度、順不同で現れます。未知のフィールド、重複したフィールド、欠けたフィールドはエラーです。値は、key:接頭辞のあとの行の残り(空でないもの)であり、前後にスペースやタブはなく、制御文字や行区切り文字も含みません。この文法における空白は ASCII のスペース(U+0020)とタブ(U+0009)だけであり、フェンス行の字下げと前後の空白でも、内容行でも同じです。実装はここでランタイムの空白クラスを使ってはなりません(MUST NOT)。それらは U+0085 や U+00A0 のような文字について食い違い、ブロックが存在するかどうかについて食い違うことになるからです。先頭の UTF-8 バイトオーダーマークは、パースの前に取り除かれます。行は LF で分割され、末尾の CR は許容されます。空行と#で始まる行全体は無視されます(content-categories.md のカテゴリインデックスのブロックと同じです)。ファイルは UTF-8 です。走査は行単位で、markdown の構造は参照しません。任意のスペースまたはタブの字下げのあとに 3 つ以上のバッククォートとタグを持つ行は、より長いフェンス付きの例の中でも、リスト項目の中でも、文書のどこにあっても本物のブロックを開きます。したがって、宣言ではなく説明のための例は別のタグでフェンスします。leji-mountsの後にトークンを足すのではありません。スキャナが照合するのはタグなので、leji-mounts exampleは本物のブロックを開いてパースエラーを報告し、textとタグ付けされたフェンスは何も開きません。mountは宣言されたマウントのnameと一致しなければならず(MUST)、ownerはそのマウントの宣言されたowner.nameと一致しなければなりません(MUST)。比較はデコードされた文字列として行われます。宣言されていないマウントのエントリ、ひとつのマウントに対する 2 つ目のエントリ、エントリのない宣言済みマウントは、いずれもエラーです。マウントを宣言していないレイヤーは、leji-mountsブロックを持ってはなりません(MUST NOT)。兄弟の場所は、意図して要素になっていません。マウントは、機械ごとの、内容アドレスによる投影として実体化されるので、読み手はパスを推測するのではなく
leji mounts locate <name>で解決します(distribution.md に従います)。ブロックの周りの散文は、経路の決め方を自然な言葉で説明すべきです(SHOULD)。ブロックは確認できる核であって、その散文やleji.jsonの宣言に取って代わるものでは決してありません。マウントされた兄弟は、名前を持つ別個の出典であり、ホストのカテゴリに統合されることはありません。ブートプロファイルがエージェントを兄弟へ導くのは、作業がその経路の条件に当てはまるか、プロファイルがそれを求めるときだけです。確認されないままの部分は意図的です。carriesとread-whenは自由記述であり、それがマウントの経路のメタデータに忠実かどうかは、ツールが検証するのではなくチームが申告します。ツールが確認するのは、列挙、同定、存在です。ここで兄弟を示すことで、マウントの発見がエージェントにとって作業の言葉のエントリポイントにとどまり、要件 5 に従うのにマニフェストを読む必要がないままになります。
leji-mounts ブロックの実例#
acme-product-context という名前のマウントを 1 つ宣言しているホストのための、エントリ 1 件です。ブロックはブートプロファイルの 1 桁目に、ここに見えるとおりに置かれます。外側のバッククォート 4 つのフェンスはこの文書の包みであって、ブロックの一部ではありません。
```leji-mounts
- mount: acme-product-context
owner: Product team
carries: product-side domain language and the decisions behind the customer-facing surface
read-when: a task touches product behavior, product terminology, or billing
```
エージェントプロファイル#
コンテキストレイヤーは、machine.agentProfilesPath が宣言するディレクトリの下に、ロールごとのプロファイル(たとえばレビュアーのプロファイル、リリースのプロファイル、QA のプロファイル)を定義しても構いません(MAY)。各プロファイルは次のとおりです。
-
agent-profile.schema.jsonに照らして妥当な YAML フロントマターを持つ markdown でなければなりません(MUST)。 -
継承を解決したあとに、そのロールが最初に読むもの(
requiredRead)と、停止して尋ねなければならない場面(mustAskWhen)を持たなければなりません(MUST)。inheritsを宣言するプロファイルは、基底がそれを供給する場合、どちらか一方を省いても構いません(MAY)。宣言しないプロファイルは、自ら両方を宣言しなければなりません(MUST)。 -
inheritsを宣言しても構いません(MAY)。これは 1.0 系列で有効です。それは、そのレイヤーのプロファイル集合の中の他のプロファイルをちょうど 1 つ名指しします。そのプロファイルのroleはcoreでなければならず(MUST)、このプロファイルはその姿勢と本文を拡張します。レイヤーのプロファイル集合とは、宣言されたmachine.agentProfilesPathの下のすべての文書と、マニフェストのagentsマップが名指しするすべての文書(それがどこにあっても)です。解決は 1 段階だけなので、roleがcoreであるプロファイルはinheritsを宣言してはなりません(MUST NOT)。また名指しされた対象は存在しなければならず(MUST)、idで一意でなければならず(MUST)、自身がinheritsを宣言してはなりません(MUST NOT)。解決は次のように合成します。- 姿勢の配列(
requiredRead、defaultContext、mustAskWhen、mustRefuseWhen): 基底のエントリを書かれた順に、続いて派生プロファイルのエントリをその順に並べ、基底がすでに持つものは落とします。書かれた順序は読み込みの意図なので、並べ替えは行いません。 - それ以外のすべてのフィールド(
id、name、role、purpose、version、host、invocation、escalation、owners、freshness): 派生プロファイル自身のものであり、継承されることは決してありません。inheritsは解決のための指示であり、それ自体は解決後のプロファイルの一部ではありません。 - 本文: どちらの本文も規範的です。基底が先、続いて派生プロファイルです。
継承されたプロファイルを解決できない利用側は、派生ファイルだけを適用してはなりません(MUST NOT)。派生ファイルはプロファイルの半分なので、利用側は代わりにそれを未対応として報告します。尋ねる条件と拒否する条件が同じ状況に当てはまる場合は、拒否が優先します。
解決が保証するのは合成であって、意味の絞り込みではありません。基底と矛盾したり基底を弱めたりする派生の散文は不適合であり、自然言語の矛盾を検出するツールは存在しません。
- 姿勢の配列(
プロファイルが調整するのは、あるロールが何を読み、どう振る舞うかです。コンテキストレイヤーの内容を複製するものではありません。
プロファイルの任意の host と invocation は、担い手がひとりの場合の簡略記法です。このロールを担う唯一の参加者にどう関与するかを述べます。その command は、<prompt> プレースホルダーとその配置を含め、アクターのコマンドテンプレートと同じ規則に従うテンプレートです(context-layer.md の要件を参照)。ひとつのロールに担える参加者が複数いる場合や、同じ参加者が担うロールによって別の起動方法を必要とする場合は、マニフェストの任意の actors レジストリが代わりにそれを持ちます(同じ節を参照)。ロールが使うのはどちらか一方の仕組みであって、両方ではありません。
補足(非規範的)#
ブートプロファイルは、意図的に単調なものです。地図と姿勢を示すものであり、知識を集積する場所ではありません。数画面を超える長さに膨らんでいるなら、本来カテゴリに属する内容がエントリポイントに入り込んでいます。
この設計が防ぐ失敗の形は、間接参照です。エージェントが最初に読むコンテキストから実際の制約までの参照が 1 段増えるたびに、注意が削がれます。適切に実装されたコンテキストレイヤーには、ベンダーのエントリポイントがまったく必要ありません(invocation からブートプロファイルを直接指定できます)。ブートプロファイルから内容へも直接たどれます。深さを持たせるべきなのはコンテキストレイヤーの文書であり、そこへ至る経路ではありません。
ブートプロファイルで「どの作業の前にも読む」と指定した文書には、作業のたびに読み込みコストがかかります。そのため、無条件の集合はコンテキストレイヤーで最もコストの高い場所です。真に普遍的なものだけに絞り、残りは作業種別ごとの読み込み、カテゴリ、インデックス、各決定記録で宣言された適用範囲を通じて導いてください。インデックスの目的は、エージェントがツリー全体ではなく、作業に必要な部分だけを読み込めるようにすることです。決定は際限なく増えるため、ディレクトリ全体を事前に読み込まず、経路によって導きます。