creating-spec について
技術仕様書を作成するためのスキルです。関連コードベースの調査と設計上の確認を先に行い、段階的な手順、文書構成、Effect-TS準拠および仕様間の整合性チェックを定めます。
主な機能
- 01複数コードベースの調査手順
- 02執筆前の設計確認
- 03仕様書の構成テンプレート
- 04Effect-TS準拠の監査
- 05仕様間の整合性チェック
- 06実装と移行の計画
活用シーン
- 01複数パッケージにまたがるモジュールの計画
- 02SDKの不足点や機能モジュールの文書化
- 03プロジェクト規約に沿った仕様書の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ pedronauck/ skills --skill creating-specインストール後、Claude Code で/creating-specを入力して読み込まれたか確認します。
詳細
仕様書の作成
散在している機能を一元化したり、SDK の不足を補ったり、新しい機能モジュールを計画したりするための、包括的な技術仕様書を作成する体系的なワークフローです。このスキルでは、セッション管理やツールレジストリブリッジの仕様書のような高品質な仕様書を作成するために実証されたプロセスを体系化しています。
<critical_rules>
必須のワークフロー
以下のフェーズを必ず順番どおりに実行してください。フェーズを省略したり、組み合わせたりすると、仕様書が不完全になります。
フェーズ 1:徹底的な調査(出力のみ、ファイルへの書き込みなし)
目標:何かを提案する前に、関連するすべてのコードベースにある既存コードの全体像を把握します。
-
並行して調査エージェントを起動します(同時に 4~5 個)。それぞれ次を担当します。
- 仕様書が実装される対象パッケージ(例:
providers/sdk) - 最も完全な実装がある参照実装(例:
providers/runtime) - 独自の実装があるコンシューマーのコードベース(例:
packages/electron/src/agents/、packages/electron/src/looper/) - 関連する型やユーティリティを含む共有パッケージ(例:
packages/types)
- 仕様書が実装される対象パッケージ(例:
-
各調査エージェントは次の内容を報告します。
- 主要な型やインターフェースを含むファイルパス
- コンポーネントの接続方法と相互作用
- 使用されているパターン(Effect サービス、Context.Tag、ファクトリーなど)
- コードベース間の重複と分断状況
-
必須:調査後、主要なファイルを直接読んで調査結果を確認します。型シグネチャや API の形式について、調査エージェントの要約だけに頼ってはいけません。
-
最初に調査結果を提示します。次の内容をユーザーに示してください。
- コードベース間の比較表(それぞれに存在するもの)
- 重複マップ(複数の場所で同じ処理をしているもの)
- 一元化すべきものと、現在の場所に残すべきもの
- 不足しているものの明確な特定
禁止事項:フェーズ 1 では、ファイルを一切書き込んではいけません。分析内容はチャットにのみ出力してください。
フェーズ 2:要件の明確化(書き始める前に質問する)
目標:仕様書のアーキテクチャに影響する設計上の決定事項を明確にします。
-
AskUserQuestion ツールを使用して、次の点について、焦点を絞った質問を 2~4 個行います。
- 対象範囲に関する決定(全面置き換え、構成要素の提供、薄いラッパーのいずれにするか)
- 自動化のレベル(完全自動、手動、ハイブリッドのいずれにするか)
- 後方互換性に関する懸念(ネイティブサポートか、コンシューマー側で処理するか)
- 一元化するモジュールに含めるものと除外するもの
-
質問の形式:
- 各質問には、説明を添えた具体的な選択肢を 2~3 個示します。
- 推奨する選択肢には「(推奨)」と明記します。
- 選択肢は、些細な好みではなく、実質的に異なるアーキテクチャ上の選択肢を表すものにします。
-
必須:回答を受け取ってから先に進みます。デフォルトを推測してはいけません。
禁止事項:一度に 4 個を超える質問をしてはいけません。仕様書に重大な影響を与える決定事項に絞ってください。
フェーズ 3:仕様書の作成
目標:適切な抽象度で包括的な仕様書を作成します。実装コードではなく、振る舞いの契約とアーキテクチャ上の決定を記述します。
-
既存の仕様書の形式を確認する — 同じディレクトリにある過去の仕様書(例:
tasks/prd-sdk/1_*.md、tasks/prd-sdk/2_*.md)を読み、確立されたスタイルと構成に合わせます。 -
仕様書を作成する — 以下のテンプレート構成に従います。
-
必須セクション(すべて含める必要があります):
- 問題の説明(何が壊れているか/重複しているか、現状どのようなコストが発生しているか)
- 設計概要(ASCII によるアーキテクチャ図、概要レベルのフロー)
- 新規ファイル(ディレクトリ構成)
- 詳細な API 仕様(インターフェース、型、サービスのタグ)
- 置き換え対象(ファイルごとに、どこがどう変わるかを対応付ける)
- 既存システムとの連携(既存の仕組みとどのように共存するか)
- 公開 API の範囲(明示的なエクスポート一覧)
- 高レベルの実装概要(利用側のコード例)
- テスト戦略(ユニットテストと統合テストの計画)
- 実装順序(依存関係と並列化を示した番号付き手順)
- 移行パス(既存の利用者向けの段階的なロールアウト)
- 移行しないもの(除外項目とその理由を明示)
フェーズ 3b:EFFECT-TS 準拠チェック
目標:仕様書をユーザーに提示する前に、すべてのコードスニペットが Effect-TS のパターンに従っていることを確認します。
必須:仕様書の作成後、すべてのコードスニペットを effect-ts および effect-ts スキルに照らして監査します。以下を確認してください。
- インポートパターン:
import * as Module from "effect/Module"を使用し、import { X } from "effect"は使用しないでください。 - ブランド型:すべてのドメインプリミティブ(ID、キー、名前)は、
Schema.String.pipe(Schema.brand("X"))でブランド化する必要があります。確立されたパターンについては、既存のprotocol/branded.tsを確認してください。 - スキーマクラスのパターン:レコードには
Schema.Classを、判別可能なバリアント(イベント、ステータス型)にはSchema.TaggedClassを使用します。既存のイベントがprotocol/events.tsでどのように定義されているかを確認し、正確に合わせてください。 Schema.Unknownは使用しない:JsonValue、JsonObject(protocol/shared.tsから)、またはSchema.Defect(外部エラーをラップする場合)を使用します。Schema.Unknownや型としての裸のunknownは使用しないでください。Schema.Enumsは使用しない:文字列リテラルのユニオンにはSchema.Literal("a", "b", "c")を使用します。Schema.Enumsは TypeScript のenum型にのみ使用します。Schema.suspendは使用しない:再帰型の場合にのみ使用します。他のスキーマを参照するためには必要ありません。- サービスのパターン:サービスでは、静的ファクトリーメソッドと静的
layerを備えたContext.Tagを使用する必要があります。サービスロジックやレイヤーファクトリーに、モジュールスコープの関数を使用しないでください。 - 静的ヘルパー:ヘルパー/ユーティリティ関数は、モジュールスコープの
export const関数ではなく、ヘルパークラスの静的メソッド(例:MyHelpers.resolve())にしてください。 Effect.fnによるトレーシング:すべてのサービスメソッドの実装では、可観測性のためにEffect.fn("ServiceName.methodName")を指定する必要があります。この要件を仕様書に明記してください。- エラー処理:ドメインエラーには
Schema.TaggedErrorを使用します。不明な外部エラーはSchema.Defectでラップします。エラーチャネルでunknownを使用しないでください。 - シークレット:API キーや機密値には、通常の
stringではなくRedacted.Redactedを使用します。 - テスト容易性:
Date.now()や生のclockコールバックではなく、Clock.currentTimeMillisを使用します。テスト時刻の制御には Effect のTestClockを使用します。 - 不変状態:サービスの状態は、ミュータブルな
Map/Setではなく、RefまたはSynchronizedRefに保持する必要があります。Effect のHashMap.HashMapを優先してください。 Schema.Classの構築:Schema.Class型のインスタンスを返す際は、プレーンなオブジェクトリテラルではなく、必ずnew ClassName({...})コンストラクターを使用します。
Phase 3c:仕様間の整合性チェック
目標:新しい仕様が、他の仕様で定義されている内容と矛盾したり、重複したりしないことを確認します。
必須:最終確定の前に、同じディレクトリ内にある既存の仕様をすべて確認してください。
- 定義を重複させない:型、定数、関数が別の仕様ですでに定義されている場合は、再定義せずにインポートしてください。重複しやすいものの例:
- プロバイダーファミリーの解決関数
- プロバイダーのメタデータキーのフォールバックマップ
- 複数の関心事にまたがる型定義
- 命名を統一する:同じ概念には、すべての仕様で同じ名前を使用してください。Spec N が
ProviderFamilyIdを定義している場合、Spec N+1 でOpenResponsesProviderFamilyと呼んではいけません。 - 型の互換性を確保する:2つの仕様が同じインターフェース(例:
CompozyCallProviderOptions)を拡張する場合、自分の仕様にあるフィールドだけでなく、すべての仕様のフィールドを列挙してください。 - 実装順序を明記する:自分の仕様が別の仕様での型拡張(例:
ProviderIdの値が3個から11個に増えること)に依存する場合は、「Implementation Order」セクションでその依存関係を明示してください。 - 正式な所有元を定める:各型、関数、定数の正式な定義元ファイルは1つだけにしてください。それを定義する仕様が所有元です。利用する他のすべての仕様には、「
src/path/file.tsからインポート(Spec N で定義)」と記載してください。
Phase 4:ハイレベル実装(依頼に応じて反復)
目標:最終的な成果の動作を示す、具体的で利用者向けの API の例を提示します。
- 仕様に「High-Level Implementation Overview」セクションを含め、以下を記載してください。
- セットアップ/設定コード
- 登録/初期化コード
- ストリーミングまたは実行時の使用方法
- ユーティリティの直接使用例(コーデック、ヘルパーなど)
- カスタムプロバイダー/拡張の例
- 依存関係の変更前/変更後の図(ASCII)
- ユーザーがこれを別途依頼した場合は、注釈付きのコードブロックを含む、簡潔なチャット形式の回答として提示してください。
</critical_rules>
<spec_template>
仕様書の構成
すべての仕様書でこの構成に従ってください。相互参照しやすいよう、各セクションに番号を付けます。
# [Feature Name] for [Target Package]
## Problem Statement
- What systems currently exist (list each with location)
- What duplication exists (table format: concern | location A | location B | location C)
- What this costs today (concrete pain points, not abstract)
## Design: [Design Name]
- Architecture diagram (ASCII art showing data flow)
- Key principle (e.g., "fully automatic", "opt-in", "plug-in")
## New Files
- Directory tree of new files to create
## 1-N. Detailed Specifications
- Each major component gets its own numbered section
- Include full TypeScript interfaces with JSDoc
- Show Effect service tags, Layer factories
- Specify error types
## N+1. What This Replaces
- Table: Current File | What Moves | What's Eliminated
- Separate tables per codebase (runtime, agents, looper)
## N+2. Interaction With Existing Systems
- How new code coexists with existing services
- What changes vs. what stays the same
## N+3. Public API Surface
- Explicit export lists from sub-path and main entry
## N+4. High-Level Implementation Overview
- Consumer-facing code examples (setup, usage, customization)
- Before/after dependency graph
## N+5. Testing Strategy
- Unit test plan per module
- Integration test plan
- Migrated tests from existing codebases
## N+6. Implementation Order
- Numbered steps with dependency column and parallelization notes
- Table format: Step | What | Depends On | Parallelizable
## N+7. Migration Path
- Phased rollout (Phase 1, 2, 3...)
- Each phase: what changes, what re-exports, what gets deleted
## N+8. What Does NOT Move
- Table: Concern | Location | Why It Stays
- Be explicit about boundaries
</spec_template>
<quality_standards>
品質チェックリスト
仕様を完成とみなす前に、以下を確認してください。
- コードベース全体の調査を実施した(対象パッケージだけではない)
- 重複マップで、重複している内容とその場所を明確に示した
- すべての設計上の決定について、AskUserQuestion を通じてユーザーの確認を得た
- TypeScript インターフェースが完全である(疑似コードではない)
- Effect-TS への準拠 — すべてのコードスニペットが Phase 3b のチェックに合格する(ブランド型、Schema パターン、サービスパターン、Effect.fn、Schema.Unknown を使用しない)
- 仕様間の整合性 — 定義の重複がなく、命名が統一され、型拡張に互換性がある(Phase 3c)
- 正式な所有元 — すべての型、関数、定数に所有元の仕様が1つだけあり、その他の仕様ではインポートする
- Effect パターンがプロジェクトの規約に従っている(Context.Tag、Layer、Schema.TaggedError)
- 実装順序に明確な依存関係の連鎖が記載されている(仕様間の依存関係を含む)
- 移行手順が段階的である(一括移行ではない)
- 移動しないもののセクションで、利用側の関心事を明示的に除外している
- ハイレベル実装で、実際の利用者向けコードを示している
- ファイルパスが既存の仕様の命名規則に従っている(例:
tasks/prd-sdk/N_feature-name.md) - 仕様を細かく規定しすぎていない — Spec-vs-Implementation テスト(以下を参照)に合格する
文章のスタイル
- 比較や対応関係には、散文ではなく表を使います
- アーキテクチャ図には、mermaid ではなく ASCII アートを使います
- インターフェースには、疑似コードではなく TypeScript コードブロックを使います
- 具体的に記述します。ファイルパス、関数名、型名を使い、「サービス」や「モジュール」といった表現は避けます
- 行数やファイル名を具体的に示し、「現状のコスト」を説明します
- 各セクションで、「何が変わり、何が変わらないのか」に答えます
Spec-vs-Implementation テスト(肥大化防止)
仕様では、システムが何をし、なぜそうするのかを記述し、行単位でどのように実装するのかは記述しないでください。すべてのコードブロックに対して、このテストを適用します。
仕様書に適切な内容(これらは維持してください):
- 型/スキーマ定義 — これらは契約そのものです(例:
Schema.Class、インターフェース、ブランド型) - インターフェースのシグネチャ — JSDoc を含むパブリック API サーフェス
- 短い振る舞いの擬似コード(15 行未満) — 主要なアルゴリズムの手順を大まかに示します
- 判断表 — プロバイダー → 設定 → 振る舞いの対応関係
- ASCII 図 — アーキテクチャ、データフロー、依存関係の変更前/変更後
- パターンごとに例を 1 つ — パターンを一度示し、「X、Y、Z に同じパターンを適用」と記します
仕様書に不適切な内容(次の内容に置き換えてください):
- 関数本体の全体(15 行超) — 振る舞いの説明に置き換えます:「X が発生したとき、システムは Y を行う必要があります」
- 繰り返しの実装(同じパターンを N 回示す) — 1 回だけ示し、バリエーションは表にまとめます
- 内部状態の型 — 内部データ構造は実装の詳細です。代わりに振る舞いを説明します
- 正確な変数名とループ構造 — 実装者の選択肢を過度に制限します
- コピーしてすぐに本番環境で使えるコード — 実装者が解釈せずコピーするようなら、詳細すぎます
肥大化したセクションの修正方法:
- コードからアーキテクチャ上の判断を抽出し、コードの上に文章で記します
- 実装コードを、振る舞いの契約、対応表、またはインターフェースのシグネチャに置き換えます
- 参考コードが本当に必要な場合は、付録に移し、「Reference Implementation Sketch (non-normative)」というラベルを付けます
- 例は 1 つのルールに従います。具体例(例:1 つの環境変数ビルダー)を示し、残りは表にまとめます
変換例:
冗長(8 つの環境変数ビルダーを 131 行で記述):
export const buildZaiEnvVars = (config: ZaiConfig): Record<string, string> => {
const env: Record<string, string> = {};
env.ANTHROPIC_BASE_URL = "https://api.zai.com/v1";
if (config.apiKey) env.ANTHROPIC_AUTH_TOKEN = config.apiKey;
// ... 15 more lines
};
export const buildOpenRouterEnvVars = (config: OpenRouterConfig): ... => { ... };
// ... 6 more builders, same pattern
適切(表+例 1 つ):
重要な判断:環境変数はリクエストごとに新しく構築します(コンストラクター時に事前計算しません)。
| プロバイダー | ベース URL | 認証変数 | 追加変数 | API_KEY をクリアするか |
|---|---|---|---|---|
| zai | https://api.zai.com/v1 | ANTHROPIC_AUTH_TOKEN | — | はい |
| openrouter | https://openrouter.ai/api/v1 | ANTHROPIC_AUTH_TOKEN | — | はい |
| ... | ... | ... | ... | ... |
すべてのビルダーは同じパターンに従います。参照:buildZaiEnvVars(上記)。
</quality_standards>
<anti_patterns>
避けるべきこと
ワークフローのアンチパターン
- 事前に調査せず仕様書を書かないでください — 重複や背景を見落とします
- 確認の段階を省略しないでください — 設計上の判断はすべてのセクションに影響します
- フェーズ 3b(Effect-TS チェック)を省略しないでください — このフェーズを省略して作成した仕様書には、どれも 5〜7 件の違反がありました
- フェーズ 3c(仕様書間のチェック)を省略しないでください — 仕様書 2 と 5 で同じ 3 つの関数が異なるシグネチャで個別に定義され、重大な矛盾が 3 件発生しました
- 以前の仕様書を読まずに仕様書を書かないでください — 形式の一貫性と型の一貫性の両方が重要です
- 確認の質問を 4 つ以上しないでください — アーキテクチャ上の判断に絞ります
内容のアンチパターン
- 曖昧なインターフェースを書かないでください — Effect パターンを含む完全な型シグネチャを記載します
- 一斉移行を提案しないでください — 常に段階的なロールアウトを採用します
- SDK に利用側の懸念事項を含めないでください — 承認ゲート、UI ストリーミング、プロンプトインジェクションは利用側にとどめます
- 「移行しないもの」のセクションを省略しないでください — 境界を明確にすることで、スコープの拡大を防げます
- 具体的なコードなしで概要だけを示さないでください — セットアップ、登録、使用方法、カスタマイズを示します
避けるべき肥大化パターン(実際の監査での指摘)
- 関数の実装全体を書かないでください — 関数本体が100行以上ある仕様(環境ビルダー、アダプター、ドライバーなど)は、アーキテクチャ上の決定を大量のコードに埋もれさせてしまいます。代わりに、動作の説明と表を使ってください。
- 同じパターンを何度も繰り返さないでください — 例は1回だけ示し、バリエーションは表にまとめてください。環境ビルダーを8回示すと131行が無駄になりますが、表と例1つなら、より明確に20行で済みます。
- 内部状態の型を指定しないでください —
RegistryStateのMapキーの形式を正確に定めるのは、実装の詳細です。「ツールセットのシグネチャごとにブリッジをキャッシュする」のように、動作上の契約を説明してください。 - そのままコピーして本番環境で使えるコードを書かないでください — 実装者がコードをそのままコピーできるなら、それは仕様ではなく実装を書いたことになります。仕様では解釈が必要になるようにしてください。
- 重要な決定をコードの中に埋もれさせないでください — 「request.model の二重の役割」に関する決定は、99行のクラス本体の中に隠れていました。コードを書く前に、まず文章で決定を明記してください。
Effect-TS で避けるべきパターン(実際の監査での指摘)
Schema.Unknownを使わないでください —JsonValue、JsonObject、またはSchema.Defectを使ってください。- ID に通常の型エイリアスを使わないでください — ブランド付きスキーマを使ってください:
Schema.String.pipe(Schema.brand("X")) - イベントに
Schema.Classを使わないでください — 判別可能なバリアント(typeフィールドを持つイベント)にはSchema.TaggedClassを使ってください。 - 文字列リテラルに
Schema.Enumsを使わないでください —Schema.Literal("a", "b", "c")を使ってください。 - モジュールスコープの関数を定義しないでください — ヘルパークラスやサービスクラスの静的メソッドを使ってください。
Schema.Classのファクトリーから通常のオブジェクトを返さないでください —new ClassName({...})コンストラクターを使ってください。- テスト可能な操作に生のコールバックを使わないでください — Effect サービスを使ってください(例:
clock?: () => numberではなくClock)。 as unknown as Xの二重キャストを使わないでください — スプレッド構文またはSchema.encodeを使ってください。
仕様間で避けるべきパターン(実際の監査での指摘)
- 別の仕様ですでに定義されている関数を再定義しないでください — インポートしてください。よくある落とし穴として、
resolveProviderMetadataのようなユーティリティ関数が複数のギャップ仕様で個別に仕様化されることがあります。 - 同じ概念に異なる名前を付けないでください —
ProviderFamilyIdとOpenResponsesProviderFamilyは混乱を招きました。名前を1つ選び、全体で統一してください。 - 共有型を拡張する際にフィールドを黙って削除しないでください — Spec 1 がオプション型に
apiKeyを追加し、Spec 2 がその型を拡張する場合は、apiKeyを含めるか、削除することを明記してください。 - 実装順序を前提にしないでください — 仕様が別の仕様による型の拡張(例:
ProviderIdの値が3個から11個に増えること)に依存する場合は、「実装順序」セクションに依存関係を記載してください。
</anti_patterns>