Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/given-scenario-guidance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@fission-ai/openspec": patch
---

### Fixed

- Standardize generated scenario guidance to include GIVEN before WHEN and THEN.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-24
26 changes: 26 additions & 0 deletions openspec/changes/standardize-given-scenario-guidance/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## Context

OpenSpec's conventions already name `GIVEN` as a scenario keyword, but the default spec template and schema instructions use `WHEN`/`THEN` examples. That means newly generated specs can drift away from the richer Given/When/Then shape even when docs describe it.

## Goals / Non-Goals

**Goals:**
- Make `GIVEN` visible in the default spec-writing path.
- Keep this change limited to templates, generated instructions, and guidance examples.
- Preserve compatibility with existing specs that omit `GIVEN`.

**Non-Goals:**
- Do not parse scenario steps into structured fields.
- Do not add validation warnings or errors for missing `GIVEN`.
- Do not rewrite the existing spec corpus.

## Decisions

- Update guidance before enforcement. This aligns generated content with the convention without causing noise in existing projects.
- Keep `GIVEN` non-breaking. The convention should encourage precondition clarity, but not require artificial preconditions where none exist.
- Update built-in schema templates and workflow examples that generate spec guidance so repo-local, workspace-planning, and sync flows teach the same structure.

## Risks / Trade-offs

- Existing examples remain mixed until separate cleanup work updates the full corpus. Mitigation: update the source templates and validation guidance first so new artifacts improve immediately.
- Agents may add vague `GIVEN` steps for simple scenarios. Mitigation: phrase guidance as initial state or preconditions rather than forcing a redundant placeholder.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## Why

OpenSpec already documents `GIVEN` as part of scenario steps, but the default spec template and generated instructions teach agents to write only `WHEN`/`THEN`. This creates inconsistent specs and weakens precondition clarity for generated requirements.

## What Changes

- Make `GIVEN` part of the default scenario guidance for newly generated specs and help examples.
- Keep existing specs valid; this change does not add parser enforcement or validation warnings.
- Clarify that `GIVEN` captures initial state or preconditions, while `WHEN` captures the trigger and `THEN` captures observable outcomes.

## Capabilities

### New Capabilities

None.

### Modified Capabilities

- `openspec-conventions`: scenario guidance should make `GIVEN` the normal first step for generated scenario examples while remaining non-breaking for existing specs.

## Impact

- `schemas/spec-driven/templates/spec.md`
- `schemas/spec-driven/schema.yaml`
- `schemas/workspace-planning/schema.yaml`
- `src/core/validation/constants.ts`
- `src/core/templates/workflows/onboard.ts`
- `src/core/templates/workflows/sync-specs.ts`
- `src/commands/schema.ts`
- `test/core/templates/skill-templates-parity.test.ts`
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## MODIFIED Requirements

### Requirement: Behavioral Spec Format

Behavioral specifications SHALL use a structured format with consistent section headers and keywords to ensure visual consistency, precondition clarity, and parseability.

#### Scenario: Writing requirement sections

- **GIVEN** an author is documenting a behavioral specification
- **WHEN** documenting a requirement in a behavioral specification
- **THEN** use a level-3 heading with format `### Requirement: [Name]`
- **AND** immediately follow with a SHALL statement describing core behavior
- **AND** keep requirement names descriptive and under 50 characters

#### Scenario: Documenting scenarios

- **GIVEN** an author is documenting a behavior or use case
- **WHEN** documenting specific behaviors or use cases
- **THEN** use level-4 headings with format `#### Scenario: [Description]`
- **AND** use bullet points with bold keywords for steps:
- **GIVEN** for initial state or preconditions
- **WHEN** for conditions or triggers
- **THEN** for expected outcomes
- **AND** for additional outcomes or conditions
- **AND** generated scenario examples SHOULD include a `GIVEN` step before `WHEN` and `THEN`

#### Scenario: Adding implementation details

- **GIVEN** a scenario step needs supporting examples or specifics
- **WHEN** a step requires additional detail
- **THEN** use sub-bullets under the main step
- **AND** maintain consistent indentation
- Sub-bullets provide examples or specifics
- Keep sub-bullets concise
11 changes: 11 additions & 0 deletions openspec/changes/standardize-given-scenario-guidance/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## 1. Guidance Updates

- [x] 1.1 Update built-in spec templates to include `GIVEN` in scenario examples.
- [x] 1.2 Update spec-driven schema instructions and examples to describe Given/When/Then format.
- [x] 1.3 Update validation remediation examples to show `GIVEN` before `WHEN` and `THEN`.
- [x] 1.4 Update generated workflow guidance that describes scenario formatting where it still implies WHEN/THEN-only.

## 2. Verification

- [x] 2.1 Validate the OpenSpec change.
- [x] 2.2 Run build, lint, and relevant tests.
5 changes: 3 additions & 2 deletions schemas/spec-driven/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ artifacts:
Format requirements:
- Each requirement: `### Requirement: <name>` followed by description
- Use SHALL/MUST for normative requirements (avoid should/may)
- Each scenario: `#### Scenario: <name>` with WHEN/THEN format
- Each scenario: `#### Scenario: <name>` with GIVEN/WHEN/THEN steps where preconditions apply
- **CRITICAL**: Scenarios MUST use exactly 4 hashtags (`####`). Using 3 hashtags or bullets will fail silently.
- Every requirement MUST have at least one scenario.

Expand All @@ -68,7 +68,8 @@ artifacts:
The system SHALL allow users to export their data in CSV format.

#### Scenario: Successful export
- **WHEN** user clicks "Export" button
- **GIVEN** the user has data available to export
- **WHEN** the user clicks "Export" button
- **THEN** system downloads a CSV file with all user data

## REMOVED Requirements
Expand Down
3 changes: 2 additions & 1 deletion schemas/spec-driven/templates/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
<!-- requirement text -->

#### Scenario: <!-- scenario name -->
- **WHEN** <!-- condition -->
- **GIVEN** <!-- initial state or precondition -->
- **WHEN** <!-- action or trigger -->
- **THEN** <!-- expected outcome -->
2 changes: 1 addition & 1 deletion schemas/workspace-planning/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ artifacts:
- **REMOVED Requirements**: Deprecated behavior with Reason and Migration.
- **RENAMED Requirements**: Name changes only; use FROM:/TO: format.

Each requirement must use SHALL/MUST language and include at least one `#### Scenario:` block.
Each requirement must use SHALL/MUST language and include at least one `#### Scenario:` block. Prefer GIVEN/WHEN/THEN steps where preconditions apply.
requires:
- proposal

Expand Down
1 change: 1 addition & 0 deletions src/commands/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,7 @@ function createDefaultTemplate(artifactId: string): string {
Description of the requirement.

#### Scenario: Example scenario
- **GIVEN** some initial state
- **WHEN** some condition
- **THEN** some outcome
`;
Expand Down
3 changes: 2 additions & 1 deletion src/core/templates/workflows/onboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,13 +296,14 @@ Here's the spec:

#### Scenario: <Scenario name>

- **GIVEN** <initial state or precondition>
- **WHEN** <trigger condition>
- **THEN** <expected outcome>
- **AND** <additional outcome if needed>

---

This format—WHEN/THEN/AND—makes requirements testable. You can literally read them as test cases.
This format—GIVEN/WHEN/THEN/AND—makes requirements testable. You can literally read them as test cases.
\`\`\`

Save to the concrete file path chosen from \`resolvedOutputPath\`.
Expand Down
4 changes: 4 additions & 0 deletions src/core/templates/workflows/sync-specs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,15 @@ This is an **agent-driven** operation - you will read delta specs and directly e
The system SHALL do something new.

#### Scenario: Basic case
- **GIVEN** relevant preconditions are met
- **WHEN** user does X
- **THEN** system does Y

## MODIFIED Requirements

### Requirement: Existing Feature
#### Scenario: New scenario to add
- **GIVEN** relevant preconditions are met
- **WHEN** user does A
- **THEN** system does B

Expand Down Expand Up @@ -243,13 +245,15 @@ This is an **agent-driven** operation - you will read delta specs and directly e
The system SHALL do something new.

#### Scenario: Basic case
- **GIVEN** relevant preconditions are met
- **WHEN** user does X
- **THEN** system does Y

## MODIFIED Requirements

### Requirement: Existing Feature
#### Scenario: New scenario to add
- **GIVEN** relevant preconditions are met
- **WHEN** user does A
- **THEN** system does B

Expand Down
4 changes: 2 additions & 2 deletions src/core/validation/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ export const VALIDATION_MESSAGES = {
GUIDE_NO_DELTAS:
'No deltas found. Ensure your change has a specs/ directory with capability folders (e.g. specs/http-server/spec.md) containing .md files that use delta headers (## ADDED/MODIFIED/REMOVED/RENAMED Requirements) and that each requirement includes at least one "#### Scenario:" block. Tip: run "openspec change show <change-id> --json --deltas-only" to inspect parsed deltas.',
GUIDE_MISSING_SPEC_SECTIONS:
'Missing required sections. Expected headers: "## Purpose" and "## Requirements". Example:\n## Purpose\n[brief purpose]\n\n## Requirements\n### Requirement: Clear requirement statement\nUsers SHALL ...\n\n#### Scenario: Descriptive name\n- **WHEN** ...\n- **THEN** ...',
'Missing required sections. Expected headers: "## Purpose" and "## Requirements". Example:\n## Purpose\n[brief purpose]\n\n## Requirements\n### Requirement: Clear requirement statement\nUsers SHALL ...\n\n#### Scenario: Descriptive name\n- **GIVEN** ...\n- **WHEN** ...\n- **THEN** ...',
GUIDE_MISSING_CHANGE_SECTIONS:
'Missing required sections. Expected headers: "## Why" and "## What Changes". Ensure deltas are documented in specs/ using delta headers.',
GUIDE_SCENARIO_FORMAT:
'Scenarios must use level-4 headers. Convert bullet lists into:\n#### Scenario: Short name\n- **WHEN** ...\n- **THEN** ...\n- **AND** ...',
'Scenarios must use level-4 headers. Convert bullet lists into:\n#### Scenario: Short name\n- **GIVEN** ...\n- **WHEN** ...\n- **THEN** ...\n- **AND** ...',
} as const;
12 changes: 6 additions & 6 deletions test/core/templates/skill-templates-parity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,19 @@ const EXPECTED_FUNCTION_HASHES: Record<string, string> = {
getContinueChangeSkillTemplate: 'fbc6c379ed3dd39f59f52b10584b8df5b1dc08b5422bcf1c6d6255a944d22a11',
getApplyChangeSkillTemplate: 'e746f230c2513a5fd40842bde494bb3cdb3c5f7c1bcece101f92090983d4ff55',
getFfChangeSkillTemplate: '50e68fbb49b76d2690b614bffa9e6210e45539fb74419fc2e4311158b6d38485',
getSyncSpecsSkillTemplate: '9f02b41227db70875b89eefeb275c769142607dc5b2593f4e606794aed2fdbad',
getOnboardSkillTemplate: '4f4b60fea6e3fc7d2185815b2808fad51535fdd00cd4401b32d1536f32fa2b6d',
getSyncSpecsSkillTemplate: '1d3189ee04c49398c1df651b6114637577d9e7fae5d74f0c6c91b153e365c2d0',
getOnboardSkillTemplate: '0bb1930d20f8f799763dcab7bc7799f558d1d8b198efc45f9c916d1456a3bf01',
getOpsxExploreCommandTemplate: '4d5e64e3ede6703113cf2fd23b797371ef2407b702478b4f7240fc81cbf2d3a5',
getOpsxNewCommandTemplate: '757f72e2d9a1a6794b2188704fd39dd2ab65428899b4b361c76cc15a5e4f2ccc',
getOpsxContinueCommandTemplate: '62f8863edda2bfe4e210f8bc3095fd4369aaaaf7772a5cba9602d0f0bca1d0c9',
getOpsxApplyCommandTemplate: '812feefd32a4d9d468e03e456d06e3d2d08d1118d29cce4911f0be59cdd30bfc',
getOpsxFfCommandTemplate: 'f775b242bcfd56594c431c7f31a0129208a1bacfdb2427074d412543072ef7ca',
getArchiveChangeSkillTemplate: 'bdf022ae2cdef1feef4d641a068bef3a7fc5d98a323f7ce9f77ac578fe8d20c6',
getBulkArchiveChangeSkillTemplate: 'fdb1715804e86de85be96222b8efeb9d5b350c6d5c19e343e244655deff8e62b',
getOpsxSyncCommandTemplate: '4c8118afaea79ff4fed3d946c88e6a7abbba904a5fbf643e4372da1e3735a467',
getOpsxSyncCommandTemplate: '27d5730661b825c6c641074576be80e6997ee8c3d6677448fde0ea1678732683',
getVerifyChangeSkillTemplate: '3c5dda8b49ba00f50b5bae7f04763dd00cc00a05e5f1d8a2068ad7fb701d8165',
getOpsxArchiveCommandTemplate: '5181ec2f59c9f0f3376e61d952ed4be976cbd01595b6b0d5e67466c8bd6bac6d',
getOpsxOnboardCommandTemplate: '57c1f3e2590bda8f47818bab1d528456c1b8a9a7501f63ab9e2115e0cfaf6f35',
getOpsxOnboardCommandTemplate: 'd257a0691a2dfe056b8797122a3322b7b804a59eee7b561d3a06ab7db08396d9',
getOpsxBulkArchiveCommandTemplate: 'b76c421023ccb5a12867c349f27cdb186234b692c1811980fb94127567bdabda',
getOpsxVerifyCommandTemplate: '9a7a3f9e5bc3d0c0878b1a4493efbbb38729597d9b9be78f63284cc2da7c20c3',
getOpsxProposeSkillTemplate: 'bae22279f8c7f711a8d5c5289551551d48197ddf5a99b695d96fff5339e08a49',
Expand All @@ -61,11 +61,11 @@ const EXPECTED_GENERATED_SKILL_CONTENT_HASHES: Record<string, string> = {
'openspec-continue-change': 'c00e2a60f79cd60197094cc59762babe5ee6a2dc1e859a0ede3f436a775ccecf',
'openspec-apply-change': 'd849442efd925b9247651e254a5cd696945321610cca5a9432ad420430554548',
'openspec-ff-change': '9d9b1995b6f4adb3da570676f7d11fee4cd1cf6c5df8ec83c033e02783a544df',
'openspec-sync-specs': '2e0f67ec6fadffc6107b4b1a28eef23a99a6649e5fae706897ea1dd9deb852a8',
'openspec-sync-specs': '8b55ffd00412ca6d3b0ab930103e584d3d49b6fa811c5da8aedead5943e7dffc',
'openspec-archive-change': '8d14af2c8b2e4358308ac9fc14f75db42a4b41a07e175825035852a82479793e',
'openspec-bulk-archive-change': '16207683996b1952559cd4e33463f28fb097761f2c5d912107733d01a90d3f2f',
'openspec-verify-change': 'a2acecd0c2b4e57080a314e5e7a093e0688293c37e446eb45d378f5050058550',
'openspec-onboard': 'b924ea3c97543ebb7ee82c5f194afe7ce87a521c32b85616f445240ab33a02ab',
'openspec-onboard': 'ab74cb7eeb5428169171e475ca7bcbe5203225193ed080bacb7d9f1c6c775d2b',
'openspec-propose': '56aa526fe1e9fac956ad3ad570a3a259d27f54b05086940d85af136a62069292',
};

Expand Down