RFC の作成とメンテナンス
このスキルは、軽量なRFC(番号付きMarkdown設計提案書)を作成し、管理します。RFCは、コードの隣にリポジトリ内で管理され、問題、現在のコードの状態、決定事項とその根拠、そして意図的にスコープ外とした事項をキャプチャします。コレクションは単一の INDEX.md で追跡され、すべての設計履歴を1つのテーブルでスキャンできます。
ここでのRFCは、作業文書であり、官僚的なものではありません。決定がコンテキストロスを乗り越えて存続し、再開された設計が「単一の小さなPR、それ以上ではない」ようにし、拒否された代替案が再議論されることがないようにするために存在します。
このスキルを使用するタイミング
- ユーザーがRFC、設計ドキュメント、設計提案、技術仕様、アーキテクチャ提案の作成を依頼した場合
- ユーザーが実装前に、設計上の決定(それが打ち負かした代替案、またはアプローチが拒否された理由を含む)を記録または確定したい場合
- ユーザーがRFCの更新(ステータス変更、実行メモ、出荷済みまたは拒否済みのマーク)を依頼した場合
- ユーザーが
rfcs/(またはrfc/)ディレクトリの作成、インデックス作成、再編成を依頼した場合 - 大規模な機能の議論を、永続的なドキュメントとしてキャプチャする必要がある場合
このスキルを使用してはいけないタイミング
- ユーザーが製品ドキュメント、README、またはユーザー向けドキュメントを希望する場合(設計提案ではない)
- ユーザーが、既に確立されたADR(アーキテクチャ決定記録)の慣習があるリポジトリでADRを希望する場合 — 代わりにその慣習に従ってください
- 変更が、コミットメッセージやPRの説明で十分に軽微な場合
ディレクトリとインデックス
場所。 RFCはリポジトリルートの単一のフラットなディレクトリに配置されます:rfcs/(推奨されるデフォルト)または rfc/。何かを作成する前に、既存の同名のディレクトリを探し、それに従ってください。どちらも存在しない場合は、rfcs/ を作成します。
Gitignoreはユーザーの判断であり、あなたの判断ではありません。 一部のプロジェクトはRFCをコミットし、他のプロジェクトはローカルの作業メモとしてgitignoreします。明示的に依頼されない限り、RFCディレクトリの .gitignore エントリを追加または削除しないでください。ディレクトリがgitignoreされている場合、INDEX.md のヘッダーにその旨を記載し(テンプレートを参照)、読者がなぜリポジトリ履歴にないのかを理解できるようにします。
INDEX.md はコレクションの信頼できる情報源です。 次の3つの項目を保持します。
- 次の空き番号が明示的に記載されています — 番号は並行して発行されると衝突するため、インデックスが次の番号を示し、RFCが作成されるたびに同じ変更で更新されます。
- インデックステーブル:
| # | Title | Status | One-line |、RFCごとに1行、番号はファイルにリンクされています。 - ステータスの凡例。
ディレクトリが存在し、この役割を担う README.md がある場合は、それをインデックスとして扱います。新しくセットアップするように依頼された場合は、INDEX.md を使用します — references/index-template.md をコピーしてください。
番号付けとファイル名
- 番号は4桁、ゼロ埋め、単調増加:
0001、0002、… - 割り当てるには:
INDEX.mdから「次の空き番号」を読み、ディレクトリのlsとクロスチェックし(インデックスは古い可能性があります)、使用されていない次の整数を取得します。 - ファイル名:
NNNN-kebab-case-title.md。ファイル名と# RFC NNNN — TitleH1 の番号を同期させてください — これらはドリフトすると、両方のリンクが壊れます。 - 既存のRFCの番号を変更しないでください。番号は識別子であり、整理するための順序ではありません。
ステータス
- 📝 Draft — 提案済み、未開始(「設計確定、需要ゲート」のRFCもDraftです)
- 🚧 In progress — 部分的に出荷済み
- ✅ Complete — 完全に出荷済み
- ❌ Rejected / withdrawn — ファイルは保持;記録された拒否は再議論を防ぎます
ステータスは、RFCヘッダーの **Status:** 行とインデックステーブルのStatus列の2か所に存在し、一致している必要があります。同じ変更で両方を更新します。
RFCの構成
新しいRFCを作成する前に references/rfc-template.md を読み、そこから開始してください。形状:
ヘッダーブロック(H1の直下、最初のセクションの前の箇条書きリスト):
**Status:**— 絵文字+単語、オプションで注釈付き(「実行準備完了 — 1つのPR」、「設計確定、未スケジュール」)**Scope:**— 密集した段落:このRFCがカバーする内容 および意図的にカバーしない内容。これは、読者が残りを読むかどうかを決めるために読む段落です。**Related:**— 触れられるコードへのリンク(リポジトリへの相対リンク)、他のRFC、先行技術、外部参照**Discussion:**(オプション) — 設計が議論された、または議論されている場所へのリンク(PR、Issue、スレッド);異議のある読者は、ドキュメントをフォークする代わりにそこへ行きます。**Origin:**(オプション) — 設計が移植された、または一般化された元の場所(ある場合)
番号付きセクション。 本格的なRFCの場合の完全なセット:
- Summary — 数文で出荷されるもの
- Motivation — 実際のコードベースからの証拠を含む問題
- Current state — 今日存在するもの、コードに対して検証済み、記憶からではない
- Goals / Non-goals — 両方を明示
- Design — コア;ワークストリームまたはコンポーネントごとのサブセクション、実際のシグネチャ/スキーマ/コードブロックを含む(設計を固定する場合)。選択が争われた場合は、拒否された代替案とその理由を保持 — 軽微な呼び出しには1文、選択が設計を形作った場合は
### Alternatives consideredサブセクション - Tests — 設計がどのように検証されるか
- Docs — それに付随するドキュメント
- Out of scope — 名前付きで 理由付き:各項目はなぜ除外され、何がそれを変更するかを述べます
- Risks — 正直な障害モード、ドキュメントが誤読されるリスクを含む
- Unresolved questions — 設計が確定したとみなされる前に解決しなければならないこと、実装が自由に解決できること;未知のものを命名することは、ビルド中に静かに解決するより優れています
- Decisions — 確定した決定の番号付きテーブル;これにより、ピックアップが安価になり、再議論が不要になります。決定が将来を非自明に制約する場合、その行はそれを述べます — ある決定の結果は、次の決定のコンテキストです
- Phasing — 最初に何が提供されるか、何が何に依存しているか
RFCの重要度に合わせてスケールします。 小さな設計確定RFCは、ヘッダーブロック、Design、Non-goals、Decisionテーブルのみで十分です。2ページのRFCを12セクションに膨らませたり、システム全体の提案を3つにまとめたりしないでください。使用するサブセットに対して、セクション番号を連続に保ちます。
文体
- すべての主張をコードに基づいて行います。 「Current state」と「Motivation」は、ファイル、行レベルの事実、測定値を引用し、相対パスでリンクします。記憶から主張するRFCは、見出しだけのフィクションです。
- 決定をその理由とともに記録し、そのコストも記録します。 決定テーブルは契約であり、本文は推論を保持します。拒否された代替案は、なぜ負けたかを一文で記録します(トレードオフとともに記録された代替案は拒否されたままになります;単に「拒否された」と記録されたものは再提案されます)。後でドアを閉じる決定は、その行でその旨を述べます。
- タイムリーさは洗練よりも優先されます。 存在する粗いRFCは、存在しない完璧なRFCよりも優れています(OxideのRFDルール:「タイムリー、洗練よりも」)。ドラフトの散文は粗くても構いませんが、Scopeの段落と決定テーブルはそうではないかもしれません。
- 限界について正直に述べます。 メカニズムが延期、ゲート、または不完全であることがわかっている場合は、読者に発見させるのではなく、RFCでその旨を述べてください。失敗閉じの表現(「拒否」、「発生」、「意図的に未スケジュール」)は、楽観的な曖昧さよりも優れています。
- 密度は長さよりも優先します。 3つの薄い段落よりも、1つの耐荷重段落を好みます。特にインデックスの1行:読者がRFCをスキップできるように、自己完結している必要があります。
ワークフロー
帳簿管理 — 番号割り当て、テンプレートからのファイル作成、インデックス行と次の空き番号の更新、ドリフト検出 — は機械的であり、scripts/rfc_index.py が手動割り当てで発生する衝突なしに実行します:
python3 scripts/rfc_index.py check # インデックスとファイル、H1とファイル名、ステータス、次の空き番号
python3 scripts/rfc_index.py next # 次の空き番号
python3 scripts/rfc_index.py new "Title" # 割り当て + テンプレートインスタンス化 + インデックス行 + バンプ
python3 scripts/rfc_index.py new "Title" --number 42 # 予約済み番号、または削除されたRFCの再作成
(パスはこのスキルのディレクトリからの相対パス;リポジトリルートからは、スクリプトは skills/rfc-writer/scripts/rfc_index.py にあります。new 以外は読み取り専用;リポジトリがカレントワーキングディレクトリでない場合は、サブコマンドの前後に --root DIR を追加してください。)思考 — 設計が何を言っているか、1行が何を主張しているか、ステータスがいつ変わるか — はあなたのものです。
A — 新しいRFCを作成する
- RFCディレクトリ(
rfcs/またはrfc/)を見つけます。存在しない場合は、最初にワークフローDを実行します。 - 次の番号を割り当て、ファイルをインスタンス化します:
rfc_index.py new "Title"— 番号を発行し、テンプレートを書き込み、インデックス行を追加し、次の空き番号の主張をバンプします。ステップ3と4はあなたのままです:テンプレートは未記入のまま残り、インデックスにはリテラルのTODO: one-line summaryが書き込まれます。手動で:インデックスから次の空き番号を読み、lsとクロスチェックします — 番号は並行して発行されると衝突します。 references/rfc-template.mdの形状から、設計の重要度に合わせてスケールしてファイルを埋めます。「Current state」を書く前に、実際のコードを調査します — これが作業の大部分です。- プレースホルダーのインデックス1行を、密度の高い自己完結型のサマリーに置き換えます。
B — 既存のRFCを更新する
- 作業が部分的または完全に出荷された場合、
**Status:**行を更新します — そして、何が出荷され、いつ出荷されたかを注釈します(「2026-06-29出荷:… P5のみ残る」)。 - 実行が設計から逸脱した場合、RFCに逸脱を記録します(ステータスノートまたは関連セクションの修正) — 歴史を静かに書き換えず、決定ログは追加専用のままにします。
- ステータス(および、形状が変更された場合は1行)をインデックステーブルに反映します。
- 拒否された設計は ❌ を取得し、ディレクトリに残ります。
C — インデックスを維持する
rfc_index.py check を実行します — これは、インデックス行のないすべてのファイルとその逆、H1とファイル名の不一致、ヘッダーとテーブルのステータスの不一致、重複番号、空いていない次の空き番号を報告します。それが指定したものを修正し(修正は判断:どのステータスが正しいか、1行をどう書くべきか)、再実行してグリーンになるまで続けます。同期していなかったものを報告します。
D — RFCディレクトリを初期化する
rfcs/を作成します(ユーザーがrfc/を希望する場合、または既に存在する場合は除く)。references/index-template.mdからINDEX.mdを作成し、プロジェクト名を記入し、次の空き番号を0001に設定します。.gitignoreには触れません — ディレクトリをコミットするか無視するかはユーザーの選択であることを述べます。
参考文献
references/rfc-template.md— セクションごとのガイダンス付きRFCスケルトン;新しいRFCを書く前に必ず読んでくださいreferences/index-template.md— INDEX.mdスケルトン;ディレクトリを初期化するときに使用します
関連スキル
altitude-docs— 設計後に出荷されるユーザー向けドキュメント;RFCのDocsセクションはそれを指しますself-audit— RFCを実行したブランチに対して、マージ前に行われる敵対的レビューkeep-a-changelog— 出荷されたものを記録します;RFCはなぜそのように構築されたかを記録します