OpenSpec デルタスペック同期:メインスペックへの変更適用
デルタスペックの変更をメインスペックに同期します。
これは エージェント駆動型 の操作です。デルタスペックを読み取り、メインスペックを直接編集して変更を適用します。これにより、インテリジェントなマージが可能になります(例:要件全体をコピーせずにシナリオを追加するなど)。
ストアの選択: ユーザーがストア(このマシンに登録されているスタンドアロンの 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 がセットアップに関するものではないケースが 1 つあります。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/ディレクトリ内)がある変更を表示します。常に次のようにアナウンスします: 「使用中の変更: 」およびオーバーライド方法(例:
/openspec-sync-specs <other>)。 -
変更コンテキストの解決
次のコマンドを実行します:
openspec status --change "<name>" --jsonJSON には
planningHome.rootが含まれています。メインスペックは<planningHome.root>/openspec/specs/にあります。以下のすべてのメインスペックパスには、ハードコードされたリポジトリパスではなく、その(ストア対応の)ルートを使用します。ストアが選択されている場合、それは現在のリポジトリではなくストアを指します。 -
デルタスペックの検索
ステータス JSON の
artifactPaths.specs.existingOutputPathsを、デルタスペックパスの唯一の情報源として使用します。specsエントリがないか、existingOutputPathsが空の場合は、同期するデルタスペックがないことを報告し、他のアーティファクトから推測したり、アーティファクトの指示を要求したり、メインスペックを作成したりせずに停止します。呼び出し元がセットを絞り込まない限り、
existingOutputPaths内のすべてのパスを同期します。呼び出し元は、existingOutputPathsから完全なエントリの明示的なリストを指定することで絞り込みます。それらの絶対値をそのままコピーします。アーカイブはこれをインラインで行い、ユーザーも同様に行うことができます(例:/specs/billing/invoices/spec.mdで終わるエントリを選択するなど)。その後、指定されたパスのみを同期し、残りのデルタスペックはそのままにします。一括アーカイブは、実装が見つからなかったデルタを除外します。そのデルタを同期してしまうと、呼び出し元が意図的に保留したメインスペックが書き込まれる可能性があります。その絞り込まれた選択を手順 4 まで引き継ぎます。完全なリストに戻すことは決してしないでください。指定されたパスがexistingOutputPathsにない場合は、同期せず、報告して停止します。黙って無視しないでください。指定されたリストが空の場合は、同期するものがないことを報告し、メインスペックを作成せずに停止します。各デルタスペックファイルには、次のようなセクションが含まれています:
## ADDED Requirements- 追加する新しい要件## MODIFIED Requirements- 既存の要件への変更## REMOVED Requirements- 削除する要件## RENAMED Requirements- 名前を変更する要件(FROM:/TO: 形式)
デルタスペックが見つからない場合は、ユーザーに通知して停止します。
-
各デルタスペックについて、メインスペックに変更を適用
最初のメインスペック書き込みの前に、現在のスペックルールスナップショットを 1 つ取得します:
- アーカイブがこのワークフローをインラインで呼び出し、
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 Requirements:
- 要件がメインスペックに存在しない場合 → 追加します
- 要件が既に存在する場合 → 一致するように更新します(暗黙の MODIFIED として扱います)
MODIFIED Requirements:
- メインスペック内の要件を見つけます
- 変更を適用します。これには以下が含まれます:
- メインスペックにまだない新しいシナリオを追加する
- 既存のシナリオを変更する
- 要件の説明を変更する
- デルタで言及されていないシナリオ/コンテンツは保持します
REMOVED Requirements:
- メインスペックから要件ブロック全体を削除します
- 機能を廃止します。次の すべて が当てはまる場合にのみ、
spec.md全体、およびディレクトリ内に他に何も残っていない場合はディレクトリも削除します:- この実行での要件の削除により、要件ブロックが残っていない;
- スペックの残りの部分は整形式である(まだ
## Purposeがある); - この同期の前にメインスペックは空ではなかった - 何も削除しなかった場合は何も変更しない;
- ファイル内の他のすべての非空白行は、タイトル、Purpose、Requirements ヘッダー、または正規の要件のステートメント、シナリオ、またはフェンスで囲まれた例として説明される;
- 変更の
.openspec.yamlがretire_capabilities: trueを宣言している; spec.mdが実際のスペックルート内に解決される(外部ファイルを削除するために機能ディレクトリのシンボリックリンクをたどらない)。 削除された要件によって要件ブロックが残らず、かつ廃止条件のいずれかが満たされない場合は、メインスペックを変更しないでください。その機能の同期を停止し、ブロック条件を報告し、ユーザーに解決方法を伝えます。空の## Requirementsセクションを作成したり残したりしないでください。マーカーのみが欠落している場合も、そのことを伝えてください。これは、ユーザーが追加することで廃止を通過させることができる唯一のものです。
- ファイルを削除すると、その
## Purposeも削除されます。その他のセクションブロックは廃止をブロックします。廃止を報告する際は Purpose を指定してください。呼び出し元のチェックアウトにスペックが存在する場合にのみ、貼り付け可能なgit checkoutを含めてください。それ以外の場合は、チェックアウト範囲のリカバリガイダンスを提供してください。
RENAMED Requirements:
- FROM 要件を見つけ、TO に名前を変更します
デルタ内の
## Purpose:- メインスペックには既に 1 つあり、それが権威です - そのままにしておきます(
openspec archiveの動作です。警告して続行します)
d. 機能がまだ存在しない場合は、新しいメインスペックを作成:
- デルタに ADDED 要件があり、手順 b で MODIFIED または RENAMED 要件によってこの機能がブロックされていない場合にのみ作成します。それ以外の場合は何も作成せず、スペックディレクトリには触れません。REMOVED のみのデルタの場合、変更の
.openspec.yamlがretire_capabilities: trueを宣言している場合は、既に廃止済みとして報告し、スペックを再作成せずに続行します。そのマーカーがない場合は、同期がブロックされたことを報告します:openspec archiveは「スペックには少なくとも 1 つの要件が必要です」というエラーで拒否します。空のデルタには同期する操作がありません。これもブロックされたとして報告します。空の## Requirementsセクションを作成しないでください。 <planningHome.root>/openspec/specs/<capability-path>/spec.mdを作成します- Purpose セクションを追加します: デルタに
## Purposeがある場合は、その本文をそのままコピーします(openspec archiveの動作です)。ない場合のみ、簡単な TBD プレースホルダーを記述します - ADDED 要件を含む Requirements セクションを追加します
- 以下の メインスペック形式リファレンス に従ってください
- アーカイブがこのワークフローをインラインで呼び出し、
-
更新されたメインスペックを検証
以前使用したのと同じ選択済みルートフラグを使用して
openspec validate --specsを実行します。検証が失敗した場合は、問題を報告し、同期が成功したと主張しないでください。 -
サマリーを表示
すべての変更を適用した後、以下を要約します:
- どの機能が更新されたか
- どのような変更が行われたか(要件の追加/変更/削除/名前変更)
- TBD Purpose プレースホルダーが残っている新しいメインスペック。今すぐ書き込まれるようにするため
- 廃止された機能。削除された
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は両方とも、メインスペックにまだあるシナリオを削除するブロックを拒否します。 - デルタが言及していないものはすべて、メインスペックの既存の順序で保持します。
[truncated for translation]