openspec-sync-specs について
OpenSpec の変更に含まれる差分仕様をメイン仕様へマージする、エージェント主導のスキルです。要件単位で変更を適用し、仕様を検証して結果や阻害要因を報告します。
主な機能
- 01同期する差分仕様の選択
- 02要件の変更をメイン仕様にマージ
- 03条件を満たす新機能のメイン仕様を作成
- 04更新した仕様を検証
- 05同期結果と阻害要因を報告
活用シーン
- 01変更の差分仕様を同期
- 02メイン仕様の要件を追加・修正
- 03マージ後に仕様を検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ fission-ai/ openspec --skill openspec-sync-specsインストール後、Claude Code で/openspec-sync-specsを入力して読み込まれたか確認します。
詳細
変更からメイン仕様へ差分仕様を同期します。
これはエージェント主導の操作です。差分仕様を読み、変更を適用するためにメイン仕様を直接編集します。これにより、要件全体をコピーせずにシナリオを追加するなど、柔軟なマージが可能になります。
ストアの選択: ユーザーがストア(このマシンに登録された、独立した OpenSpec リポジトリ)を指定した場合、または作業対象がストア内にある場合は、openspec store list --json を実行して登録済みストア ID を確認し、仕様や変更を読み書きするコマンド(new change、status、instructions、list、show、validate、archive、doctor、context、schemas、view)に --store <id> を指定します。一度選択したら、以降のワークフローでも --store <id> を指定し続けてください。以下に示すこれらのコマンドの例でストア指定がないものは、すべてフラグを付けて実行してください。たとえば、以下に示すストア指定なしの形式ではなく、openspec status --change "<name>" --json --store "<id>" を実行します。ほかのコマンドではこのフラグは使用しません。コマンドが出力するヒントにはすでにフラグが含まれています。後続のコマンドでもそのまま指定してください。ストアを指定しない場合、コマンドは最も近いローカルの openspec/ ルートを対象にします。
プロジェクトの確認: これらの手順は、OpenSpec をすでに使用しているプロジェクトを対象としています。最初に何かを書き込む手順(new change、archive、sync specs、または成果物ファイルの作成)に進む前に、プロジェクトにルートがあることを確認してください。openspec list --json を実行し(ストアを選択している場合は、ストアがルートになるため --store <id> を指定します)、root を読み取ります。root がオブジェクトなら、プロジェクトはセットアップ済みです。"root": null なら未セットアップであり、ここに openspec/ ディレクトリはありません。openspec new change などの書き込み操作を実行すると、副作用としてディレクトリが作成されます。このコマンドはゼロ以外の終了コードも返しますが、これは CLI の故障ではなく、その状態を示すものです。再試行したり回避策を試したりせず、JSON を読み取ってください。
"root": null でも、セットアップの問題ではない場合があります。status のエラーメッセージが Declared in または Invalid store declaration in で始まり、このプロジェクトの openspec/config.yaml(または config.yml)を示している場合、プロジェクトは宣言済みストアを介して OpenSpec を使用していますが、このマシンからは解決できません(ストアが登録されていない、または store: の行の形式が正しくない)。未初期化として扱って以下の分岐に進むのではなく、書き込みを行う前に停止し、そのエラーの message と fix をユーザーに提示してください。
それ以外でルートがない場合、次の対応はこのワークフローに至った経緯によって異なります。
- 自動選択: ユーザーが OpenSpec に言及したり、このスキルを指定したり、スラッシュコマンドを実行したりせず、自分でこのワークフローを選んだ場合です。OpenSpec の使用を中止し、OpenSpec がインストールされていない場合と同様に、通常どおりリクエストに回答してください。セットアップするよう求めたり、OpenSpec のセットアップについて言及したりしないでください。
- 明示的な OpenSpec のリクエスト: ユーザーが OpenSpec に言及した場合、このスキルを指定した場合、またはスラッシュコマンドを実行した場合です。書き込みを行う前に停止し、どう進めるかを尋ねてください。このプロジェクトをセットアップする(
openspec init)、すでにあるストアを対象にする(--store <id>)、またはこのリクエストでは OpenSpec を使わずに続行する、という選択肢を提示します。ユーザーの回答を待ってください。
どちらの分岐でも、副作用としてルートを作成してはいけません。ユーザーに求められるまで openspec init を実行せず、openspec/ ファイルを手動で作成せず、コマンドによって作成されることも避けてください。
<capability-path> は specs/ からの相対パスで表した仕様ディレクトリです(例:user-auth または identity/user-auth)。メイン仕様を特定する際は、各差分仕様のフルパスを維持してください。
入力: 変更名を指定できます。省略された場合は、会話の文脈から推測できるか確認してください。曖昧な場合、または候補が絞れない場合は、利用可能な変更をユーザーに尋ねる必要があります。
手順
-
変更を選択する
名前が指定されている場合は、それを使用します。指定されていない場合:
- ユーザーが会話の中で変更について言及していれば、そこから推測します
- アクティブな変更が 1 つだけの場合は、自動選択します
- 曖昧な場合は、
openspec list --jsonを実行して利用可能な変更を確認し、ユーザーに選択を求めます
選択を求める際は、差分仕様が含まれる変更(
specs/ディレクトリ内)を表示してください。 必ずアナウンスしてください: "Using change: " と、その上書き方法(例:/openspec-sync-specs <other>)。 -
変更コンテキストを解決する
実行:
openspec status --change "<name>" --jsonこの JSON には
planningHome.rootが含まれます。メインスペックは<planningHome.root>/openspec/specs/の下にあります。以下のすべてのメインスペックパスには、ハードコードされたリポジトリパスではなく、その(ストア対応の)ルートを使用してください。ストアが選択されている場合、それは現在のリポジトリではなく、そのストアを指します。 -
デルタスペックを検索する
ステータス JSON の
artifactPaths.specs.existingOutputPathsを、デルタスペックパスの唯一の情報源として使用してください。specsエントリが存在しないか、existingOutputPathsが空の場合は、同期するデルタスペックがないことを報告し、他のアーティファクトから推測せず、アーティファクト命令を要求したりメインスペックを書き込んだりせずに停止してください。呼び出し元が集合を絞り込んでいない限り、
existingOutputPaths内のすべてのパスを同期してください。呼び出し元は、existingOutputPathsから完全なエントリの明示的なリストを指定することで絞り込みます。それらの絶対値をそのままコピーしてください。Archive はこれをインラインで行い、ユーザーも同様に行えます(たとえば、/specs/billing/invoices/spec.mdで終わるエントリを選択するなど)。 その後、指定されたパスのみを同期し、残りのデルタスペックは変更しないでください。一括アーカイブでは、実装が見つからなかったデルタは除外され、それでも同期すると、呼び出し元が意図的に除外したメインスペックが書き込まれてしまいます。その絞り込まれた選択をステップ 4 まで引き継ぎ、完全なリストに戻さないでください。指定されたパスがexistingOutputPathsにない場合は、それを同期しないでください。黙って破棄するのではなく、報告して停止してください。指定されたリストが空の場合は、同期するものがないことを報告し、メインスペックを書き込まずに停止してください。各デルタスペックファイルには、次のようなセクションが含まれます:
## ADDED Requirements- 追加する新しい要件## MODIFIED Requirements- 既存の要件への変更## REMOVED Requirements- 削除する要件## RENAMED Requirements- 名前を変更する要件(FROM:/TO: 形式)
デルタスペックが見つからない場合は、ユーザーに通知して停止してください。
-
各デルタスペックについて、メインスペックに変更を適用する
最初のメインスペック書き込みの前に、現在の specs ルールスナップショットを 1 つ取得してください:
- Archive がこのワークフローをインラインで呼び出し、
openspec instructions specs --change "<name>" --jsonから有効なスナップショットを提供した場合は、それを再利用し、同じ命令を再度取得しないでください。 - それ以外の場合は、同じ選択ルートフラグを付けて、そのコマンドを今 1 回実行してください。
- 直接参照が非ゼロで終了するか、無効なアーティファクト命令 JSON を返した場合は、エラーを報告し、メインスペックを書き込む前に停止してください。その失敗を、ルールセットが存在しないものとして扱わないでください。
rulesが省略された有効なレスポンスは、アーティファクトルールが設定されていないことを意味し、既存のセマンティックマージが続行されます。
返された
rulesは、このマージによって生成されるメインスペックの内容と形式にのみ適用してください。アーティファクトルールは操作ガイダンスではなく、選択されたルート、デルタパス、CLI チェック、ワークフローのステップを変更することはできません。そのテキストを制約として使用し、メインスペックやサマリーにそのままコピーしないでください。ステップ 3 で選択された各ケイパビリティのデルタスペックパスについて — 完全な
existingOutputPathsリスト、または呼び出し元が指定した場合は絞り込まれたサブセット(これらはリポジトリではなく、選択されたストアに属する場合があります):a. デルタスペックを読み取る 意図された変更を理解するため
b. メインスペックを読み取る
<planningHome.root>/openspec/specs/<capability-path>/spec.md(まだ存在しない場合があります)まだ存在しない場合(新しいケイパビリティ)、
openspec archiveの動作に合わせてください: ADDED 要件のみを適用できます — ステップ d がそれらからスペックを作成します。 MODIFIED と RENAMED には作用する要件がないため、そのケイパビリティの同期を停止し、そのメインスペックが存在せず、新しいスペックには ADDED のみが許可されることを報告してください。欠落している要件を決してでっち上げないでください。REMOVED には削除するものがありません — スキップして警告してください。 c. 変更をインテリジェントに適用する:ADDED 要件:
- 要件がメインスペックに存在しない場合 → 追加する
- 要件がすでに存在する場合 → 一致するように更新する(暗黙の MODIFIED として扱う)
MODIFIED 要件:
- メインスペック内の要件を探す
- 変更を適用する - これは次のいずれかです:
- メインスペックにまだない新しいシナリオを追加する
- 既存のシナリオを変更する
- 要件の説明を変更する
- デルタで言及されていないシナリオ/内容は保持する
REMOVED 要件:
- メインスペックから要件ブロック全体を削除する
- ケイパビリティを廃止する。次のすべてが成り立つ場合にのみ、
spec.md全体を削除する - そして、そこに他に何も残らなくなったらディレクトリも削除する:- 今回の実行で要件を削除した結果、要件ブロックが残っていない;
- スペックの残りの部分が整形式である(
## Purposeがまだある); - この同期の前にメインスペックがすでに空だったわけではない - 何も削除しなかったなら、何も変更しない;
- ファイル全体の他のすべての空でない行が、タイトル、Purpose、Requirements ヘッダー、または正規の要件のステートメント、シナリオ、フェンス付きの例として説明できる;
- 変更の
.openspec.yamlがretire_capabilities: trueを宣言している; spec.mdが実際の specs ルート内に解決される(外部ファイルを削除するためにケイパビリティディレクトリのシンボリックリンクをたどらない)。 選択した要件を削除すると要件ブロックが残らなくなり、廃止条件のいずれかが満たされない場合は、メインスペックを変更しないでください。そのケイパビリティの同期を停止し、ブロックしている条件を報告し、ユーザーにその解決方法を伝えてください。空の## Requirementsセクションを書いたり残したりしないでください。 マーカーだけが欠けている場合は、そのことも伝えてください - それはユーザーが追加して廃止を実行できるようにするための唯一のものです。
- ファイルを削除すると
## Purposeも削除されます; その他のセクションがあると廃止がブロックされます。廃止を報告するときは Purpose を明示してください。ペースト可能なgit checkoutを含めるのは、スペックが呼び出し元のチェックアウト内にあった場合だけにしてください; それ以外の場合はチェックアウトにスコープされた復旧ガイダンスを示してください。
RENAMED 要件:
- FROM 要件を探し、TO に名前を変更する
デルタ内の
## Purpose:- メインスペックにはすでに存在し、それが権威です - そのままにしてください
(これが
openspec archiveの動作です; 警告して次に進みます)
d. 新しいメインスペックを作成する(ケイパビリティがまだ存在しない場合):
- デルタにそれを入れる ADDED 要件があり、ステップ b でこのケイパビリティをブロックした MODIFIED または RENAMED 要件がない場合にのみ行います。それ以外の場合は何も作成せず、specs ディレクトリを変更しないでください。REMOVED のみのデルタの場合、変更の
.openspec.yamlがretire_capabilities: trueを宣言しているなら、すでに廃止済みとして報告し、スペックを再作成せずに続行してください。そのマーカーがない場合は、同期をブロックされているものとして報告してください:openspec archiveはそれをSpec must have at least one requirementで拒否します。 空のデルタには同期する操作がありません; これもブロックされているものとして報告してください。 空の## Requirementsセクションを書かないでください。 <planningHome.root>/openspec/specs/<capability-path>/spec.mdを作成する- Purpose セクションを追加する: デルタに
## Purposeがあればその本文をそのままコピーする (これがopenspec archiveの動作です); ない場合にのみ簡単な TBD プレースホルダーを書く - ADDED 要件を含む Requirements セクションを追加する
- 以下の メインスペック形式リファレンス に従う
- Archive がこのワークフローをインラインで呼び出し、
-
更新されたメインスペックを検証する
先ほど使用したものと同じ選択ルートのフラグを付けて
openspec validate --specsを実行します。 検証が失敗した場合は、問題を報告し、同期が成功したと主張しないでください。 -
サマリーを表示する すべての変更を適用した後、以下を要約します。
- 更新された機能
- 行った変更(追加/変更/削除/名称変更した要件)
- Purpose が TBD のプレースホルダーのままになっている新しいメイン仕様があれば、後回しにせず今すぐ記述できるようにします
- 廃止された機能があれば、削除した
spec.mdとその Purpose を示し、貼り付けて実行できるgit checkoutコマンド、またはチェックアウト対象を限定した復元方法を記載します
差分仕様の形式に関する参考資料
# Spec Delta
## Purpose
Only on a delta that introduces a brand-new capability. Seeds the new main spec.
## ADDED Requirements
### Requirement: New Feature
The system SHALL do something new.
#### Scenario: Basic case
- **WHEN** user does X
- **THEN** system does Y
## MODIFIED Requirements
### Requirement: Existing Feature
The system SHALL keep doing the existing thing, now also handling A.
#### Scenario: Scenario the main spec already has
- **WHEN** user does X
- **THEN** system does Y
#### Scenario: New scenario to add
- **WHEN** user does A
- **THEN** system does B
## REMOVED Requirements
### Requirement: Deprecated Feature
## RENAMED Requirements
- FROM: `### Requirement: Old Name`
- TO: `### Requirement: New Name`
メイン仕様の形式に関する参考資料
メイン仕様は差分がマージされる先です。デルタ操作の見出し(## ADDED/MODIFIED/REMOVED/RENAMED Requirements)を含めてはいけません。同期後、すべての要件は単一の ## Requirements セクションの下に記述されます。
# <capability> Specification
## Purpose
Short description of what this capability does and why it exists.
## Requirements
### Requirement: New Feature
The system SHALL do something new.
#### Scenario: Basic case
- **WHEN** user does X
- **THEN** system does Y
重要な原則:適切にマージする
プログラムによるマージとは異なり、上書きではなくマージします。
- MODIFIED ブロックには、要件全体(本文と、変更後も残るすべてのシナリオ)が含まれます。
openspec validateとopenspec archiveは、メイン仕様にまだ存在するシナリオを削除するものを拒否します。 - 差分で言及されていない内容はすべて、メイン仕様の既存の順序を保ったまま残します
- 変更を適切にマージするため、判断を働かせます
成功時の出力
## Specs Synced: <change-name>
Updated main specs:
**<capability-1>**:
- Added requirement: "New Feature"
- Modified requirement: "Existing Feature" (added 1 scenario)
**<capability-2>**:
- Created new spec file
- Added requirement: "Another Feature"
Main specs are now updated. The change remains active - archive when implementation is complete.
ガードレール
- 変更を行う前に、差分仕様とメイン仕様の両方を読みます
- 差分で言及されていない既存の内容を保持します
- 差分ファイルをそのままメイン仕様にコピーしてはいけません。メイン仕様が「メイン仕様の形式に関する参考資料」の構造を保ち、デルタ操作の見出しを含まないよう、内容をマージします
- 不明な点があれば、確認を求めます
- 変更内容を作業の進行に合わせて提示します
- 操作は冪等である必要があります。同じ操作を2回実行しても、結果は変わりません
artifactPaths.specs.existingOutputPathsのみを使用し、関連のないアーティファクトから差分仕様を推測してはいけません- 呼び出し元から
existingOutputPathsのサブセットが指定された場合は、それに従い、完全なリストに戻してはいけません - 仕様を直接同期する場合は仕様の指示を一度取得します。アーカイブから提供されたスナップショットがある場合は、それをその場で再利用します
- 仕様の指示を取得した際、終了コードがゼロ以外、または JSON が無効の場合は、各メイン仕様への書き込み前に処理を停止します
- アーティファクトのルールは書き込み対象の仕様のみに適用され、出力ファイルにコピーされることはありません