-
Notifications
You must be signed in to change notification settings - Fork 4.3k
feat(skills): propose /opsx:update planning-artifact update skill #1278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 7 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
c8b72fc
docs(openspec): propose add-update-workflow — graph-driven /opsx:upda…
clay-good 090d06a
docs(openspec): make add-update-workflow deterministic & grounded (Ta…
clay-good 58511fc
docs(openspec): harden add-update-workflow determinism; drop direct n…
clay-good 7dbd733
docs(openspec): full issue/PR/discussion coverage + command-family de…
clay-good d85730e
docs(openspec): resolve open questions to committed decisions; drift …
clay-good bf0705a
docs(openspec): harden add-update-workflow — close cross-OS, read-onl…
clay-good ae743a4
docs(openspec): pin data contracts + digest forward-compat; delineate…
clay-good b2f8639
docs(openspec): simplify add-update-workflow to a thin /opsx:update s…
clay-good 28a0af5
docs(update-workflow): pin the status path contract to existingOutput…
clay-good be92e8a
docs(update-workflow): address review — default profile, next-step gu…
clay-good f5ed1bb
feat(skills): implement the /opsx:update skill (openspec-update-change)
clay-good 4afe55b
Merge upstream main into add-update-workflow
clay-good File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| schema: spec-driven | ||
| created: 2026-06-29 |
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
79 changes: 79 additions & 0 deletions
79
openspec/changes/add-update-workflow/specs/artifact-graph/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: Direct Dependent Query | ||
|
|
||
| The system SHALL identify which artifacts directly depend on a given artifact (the reverse of the `requires` relationship). | ||
|
|
||
| #### Scenario: Artifact with dependents | ||
|
|
||
| - **WHEN** artifact B requires artifact A and getDependents("A") is called | ||
| - **THEN** the result includes B | ||
|
|
||
| #### Scenario: Artifact with no dependents | ||
|
|
||
| - **WHEN** no artifact requires artifact T and getDependents("T") is called | ||
| - **THEN** the result is empty | ||
|
|
||
| #### Scenario: Unknown artifact id | ||
|
|
||
| - **WHEN** getDependents() is called with an id not present in the schema | ||
| - **THEN** the system throws an error identifying the unknown id | ||
|
|
||
| ### Requirement: Transitive Downstream Query | ||
|
|
||
| The system SHALL compute the transitive set of artifacts that depend on a given artifact, returned in topological order so each artifact appears after the upstreams it depends on. | ||
|
|
||
| #### Scenario: Linear chain downstream | ||
|
|
||
| - **WHEN** artifacts form a linear chain (A → B → C) and getDownstream("A") is called | ||
| - **THEN** the result is [B, C] in that order | ||
|
|
||
| #### Scenario: Diamond downstream order | ||
|
|
||
| - **WHEN** artifacts form a diamond (A → B, A → C, B → D, C → D) and getDownstream("A") is called | ||
| - **THEN** the result includes B and C before D | ||
|
|
||
| #### Scenario: Leaf artifact has no downstream | ||
|
|
||
| - **WHEN** getDownstream() is called on an artifact with no dependents | ||
| - **THEN** the result is empty | ||
|
|
||
| #### Scenario: Downstream excludes the artifact itself | ||
|
|
||
| - **WHEN** getDownstream("A") is called | ||
| - **THEN** the result does not include A | ||
|
|
||
| ### Requirement: Artifact Content Digest | ||
|
|
||
| The system SHALL compute a deterministic content digest for an artifact from its output file(s), such that the same content yields the same digest on every run and on every platform. For an artifact with multiple output files (a glob), the digest SHALL be computed over the files ordered by their change-relative path expressed with forward slashes, and SHALL incorporate each file's relative path together with its content, so that the digest is stable regardless of the operating system's absolute-path sorting, separators, or drive letters. Content SHALL be line-ending-normalized (CRLF to LF) before hashing so that otherwise-identical content produces an identical digest regardless of encoding. | ||
|
|
||
| #### Scenario: Identical content yields identical digest | ||
|
|
||
| - **WHEN** an artifact's output content is unchanged between two computations | ||
| - **THEN** the digest is identical | ||
|
|
||
| #### Scenario: Changed content yields a different digest | ||
|
|
||
| - **WHEN** an artifact's output content changes | ||
| - **THEN** the digest changes | ||
|
|
||
| #### Scenario: Line endings do not affect the digest | ||
|
|
||
| - **WHEN** the same content is encoded with CRLF on one platform and LF on another | ||
| - **THEN** the digest is identical on both | ||
|
|
||
| #### Scenario: Glob output digest is stable across platforms | ||
|
|
||
| - **WHEN** an artifact generates a glob pattern (e.g. `specs/**/*.md`) with multiple files | ||
| - **THEN** the digest orders the files by change-relative forward-slash path before hashing | ||
| - **AND** the digest is identical on Windows and POSIX for the same file set and contents | ||
|
|
||
| #### Scenario: Renaming a file within a glob changes the digest | ||
|
|
||
| - **WHEN** a file in a glob artifact is renamed or moved (same total content, different relative path) | ||
| - **THEN** the digest changes, because the relative path is part of the hash | ||
|
|
||
| #### Scenario: Missing output has no digest | ||
|
|
||
| - **WHEN** an artifact's output does not exist on disk | ||
| - **THEN** no digest is reported for that artifact | ||
99 changes: 99 additions & 0 deletions
99
openspec/changes/add-update-workflow/specs/cli-artifact-workflow/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: Status Includes Dependency Edges | ||
|
|
||
| The system SHALL include each artifact's dependency edges in the `openspec status --json` output, so consumers can determine how artifacts relate without hardcoding artifact names. | ||
|
|
||
| #### Scenario: Status JSON exposes requires and dependents | ||
|
|
||
| - **WHEN** the user runs `openspec status --change <id> --json` | ||
| - **THEN** each artifact in the `artifacts` array includes a `requires` array (the artifact ids it depends on) | ||
| - **AND** each artifact includes a `dependents` array (the artifact ids that directly depend on it) | ||
|
|
||
| #### Scenario: Edges reflect the active schema | ||
|
|
||
| - **WHEN** the change uses a custom schema with non-default artifact ids | ||
| - **THEN** the `requires` and `dependents` edges in the status output use that schema's artifact ids | ||
|
|
||
| ### Requirement: Content Digest and Drift Reporting | ||
|
|
||
| The system SHALL report a deterministic per-artifact content digest and a drift signal in the read-only `openspec status --json` output, the drift signal computed by comparing each artifact's recorded upstream-digest baseline against the current upstream digests, so consumers can detect content changes reproducibly without relying on filesystem timestamps. Recording the baseline SHALL be a separate, explicit write operation; `openspec status` SHALL remain read-only and never mutate the baseline. | ||
|
|
||
| #### Scenario: Present artifact reports a digest | ||
|
|
||
| - **WHEN** the user runs `openspec status --change <id> --json` and an artifact's output exists | ||
| - **THEN** that artifact's status JSON includes a `digest` derived from its output content | ||
|
|
||
| #### Scenario: Digest is stable across runs | ||
|
|
||
| - **WHEN** `openspec status --change <id> --json` is run twice without the artifact's content changing | ||
| - **THEN** the artifact's `digest` is identical between runs | ||
|
|
||
| #### Scenario: Missing output reports no digest | ||
|
|
||
| - **WHEN** an artifact's output does not exist | ||
| - **THEN** the artifact's status JSON omits `digest` (or reports it as null) | ||
|
|
||
| #### Scenario: Drift reported against a recorded baseline | ||
|
|
||
| - **WHEN** an upstream dependency's current digest differs from the value recorded in an artifact's baseline | ||
| - **THEN** the artifact's status JSON reports it as drifted, listing the upstream ids whose digest changed | ||
|
|
||
| #### Scenario: Drift is unknown without a baseline | ||
|
|
||
| - **WHEN** an artifact has no recorded baseline | ||
| - **THEN** the artifact's status JSON reports drift as `unknown` rather than drifted or clean | ||
|
|
||
| #### Scenario: Drift is unknown when the baseline scheme is unrecognized | ||
|
|
||
| - **WHEN** an artifact's recorded baseline uses a digest scheme the current version does not recognize | ||
| - **THEN** the artifact's status JSON reports drift as `unknown` rather than comparing across schemes | ||
| - **AND** re-recording the baseline restores a comparable drift signal | ||
|
|
||
| #### Scenario: Recording a baseline is an explicit write, separate from status | ||
|
|
||
| - **WHEN** the baseline is recorded for an artifact via the dedicated record operation | ||
| - **THEN** the system stores the current digests of that artifact's direct upstream dependencies as its baseline | ||
| - **AND** running `openspec status` does not by itself create or change any baseline | ||
|
|
||
| #### Scenario: Missing upstream is recorded as absent | ||
|
|
||
| - **WHEN** an artifact's baseline is recorded while one of its direct upstreams has no output | ||
| - **THEN** that upstream is recorded as absent | ||
| - **AND** later creating that upstream's output reports the artifact as drifted | ||
|
|
||
| ### Requirement: Downstream Impact Query | ||
|
|
||
| The system SHALL provide an impact selector on the status command that returns the downstream artifacts affected by a change to a given artifact, in revisit (topological) order. | ||
|
|
||
| #### Scenario: Impact returns ordered downstream set | ||
|
|
||
| - **WHEN** the user runs `openspec status --change <id> --impact <artifact> --json` | ||
| - **THEN** the output lists the transitive downstream dependents of `<artifact>` in topological (build) order | ||
| - **AND** the listed artifacts include their resolved output paths and content digests so a consumer can read and rewrite them | ||
|
|
||
| #### Scenario: Impact ordering is deterministic | ||
|
|
||
| - **WHEN** the impact query is run repeatedly for the same change and artifact | ||
| - **THEN** the downstream set and its order are identical every time | ||
|
|
||
| #### Scenario: Impact entries indicate which downstream artifacts exist | ||
|
|
||
| - **WHEN** some transitive downstream artifacts have not been created yet | ||
| - **THEN** each impact entry reports its status (e.g. done vs. not-yet-created) | ||
| - **AND** a consumer can tell which downstream artifacts exist to revise versus which would need to be created | ||
|
|
||
| #### Scenario: Impact on a leaf artifact | ||
|
|
||
| - **WHEN** the impact selector targets an artifact with no dependents | ||
| - **THEN** the downstream set is empty | ||
|
|
||
| #### Scenario: Impact on an unknown artifact | ||
|
|
||
| - **WHEN** the impact selector names an artifact id not in the change's schema | ||
| - **THEN** the command reports an error identifying the unknown artifact id | ||
|
|
||
| #### Scenario: Default human-readable output is unchanged | ||
|
|
||
| - **WHEN** the user runs `openspec status --change <id>` without `--json` or `--impact` | ||
| - **THEN** the default human-readable status output is unchanged from prior behavior |
111 changes: 111 additions & 0 deletions
111
openspec/changes/add-update-workflow/specs/opsx-update-skill/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: Update Workflow Command | ||
|
|
||
| The system SHALL provide a `/opsx:update` workflow skill that revises a change's existing planning artifacts in place. It SHALL NOT advance the build frontier (it does not create a not-yet-started artifact) and SHALL edit planning artifacts only, never implementation code. | ||
|
|
||
| #### Scenario: Select the change to update | ||
|
|
||
| - **WHEN** the user invokes `/opsx:update` without a change name | ||
| - **THEN** the skill infers the change from conversation context if possible | ||
| - **AND** if it cannot, it lists available changes (most-recently-modified first) and asks the user to choose, never auto-selecting | ||
|
|
||
| #### Scenario: Revise without advancing the frontier | ||
|
|
||
| - **WHEN** the user asks `/opsx:update` to revise an existing artifact | ||
| - **THEN** the skill updates that artifact and only its already-existing downstream dependents | ||
| - **AND** it does NOT create any artifact that does not yet exist (that remains the job of `/opsx:continue`/`/opsx:propose`) | ||
|
|
||
| #### Scenario: Absent downstream artifacts are deferred to continue | ||
|
|
||
| - **WHEN** the impact set includes downstream artifacts that have not been created yet | ||
| - **THEN** the skill revises only the downstream artifacts that currently exist | ||
| - **AND** it notes the not-yet-created downstream artifacts and points the user to `/opsx:continue` to create them | ||
|
|
||
| #### Scenario: Update stays within the plan | ||
|
|
||
| - **WHEN** revising artifacts would imply changes to implementation code | ||
| - **THEN** the skill updates the planning artifacts only | ||
| - **AND** it directs the user to `/opsx:apply` to carry the revised plan into code, rather than editing code itself | ||
|
|
||
| ### Requirement: Graph-Driven Propagation | ||
|
|
||
| The `/opsx:update` skill SHALL determine which artifacts are related, in what order to revisit them, and where they live by reading the change's artifact graph and resolved paths from the CLI, and SHALL NOT rely on hardcoded artifact names or assumed path separators. This makes the skill correct for custom schemas and on every platform, not only the default `spec-driven` schema. | ||
|
|
||
| #### Scenario: Propagate to downstream dependents in revisit order | ||
|
|
||
| - **WHEN** the user changes a given artifact | ||
| - **THEN** the skill obtains that artifact's downstream dependents and their revisit order from the CLI (`openspec status --impact <artifact> --json`) | ||
| - **AND** it reviews each downstream artifact against its now-changed upstreams, in that order | ||
|
|
||
| #### Scenario: Does not compute the file list or order itself | ||
|
|
||
| - **WHEN** the skill needs to know which artifacts are affected and in what order | ||
| - **THEN** it uses the set and order returned by the CLI | ||
| - **AND** it does not enumerate, order, or filter artifacts by its own logic or by assumed artifact names | ||
|
|
||
| #### Scenario: Works for a custom schema | ||
|
|
||
| - **WHEN** the active change uses a custom schema whose artifact ids are not `proposal`/`specs`/`design`/`tasks` | ||
| - **THEN** the skill uses the artifact ids and dependency edges reported by the CLI | ||
| - **AND** propagation works without any change to the skill | ||
|
|
||
| #### Scenario: Resolve artifact paths cross-platform | ||
|
|
||
| - **WHEN** the skill reads or writes an artifact on macOS, Linux, or Windows | ||
| - **THEN** it uses the resolved path provided by the CLI status/instructions output | ||
| - **AND** it does not assume forward-slash separators | ||
|
|
||
| ### Requirement: Cohesive Audit Mode | ||
|
|
||
| The `/opsx:update` skill SHALL support an audit mode that reviews a whole change for artifacts that have drifted from or are incoherent with their upstream dependencies and offers to fix them, using the deterministic signals the CLI provides rather than its own heuristics. | ||
|
|
||
| #### Scenario: Audit reports drifted artifacts when a baseline exists | ||
|
|
||
| - **WHEN** the user invokes `/opsx:update` in audit mode and a recorded digest baseline exists | ||
| - **THEN** the skill uses the CLI's drift report (current upstream digest vs. recorded baseline) to identify which downstream artifacts to review | ||
| - **AND** it presents them in revisit order | ||
|
|
||
| #### Scenario: Audit falls back to structural facts without a baseline | ||
|
|
||
| - **WHEN** no digest baseline has been recorded for the change | ||
| - **THEN** the skill does not guess at staleness | ||
| - **AND** it surfaces the deterministic structural facts the CLI reports (an artifact whose output is missing or empty, or one still blocked/incomplete) and asks the user how to proceed | ||
|
|
||
| #### Scenario: Audit performs cross-artifact semantic review | ||
|
|
||
| - **WHEN** audit mode runs | ||
| - **THEN** in addition to the deterministic drift and structural signals, the skill reviews the change's artifacts against each other for cross-artifact incoherence that those signals cannot detect — for example a scope item present in the proposal but excluded in design, behavior specified only in design but absent from the specs, or a task duplicating an existing capability | ||
| - **AND** it presents such findings for the user to confirm before any edit | ||
|
|
||
| #### Scenario: Audit offers per-artifact fixes | ||
|
|
||
| - **WHEN** audit mode identifies one or more artifacts to revise | ||
| - **THEN** the skill proposes a concrete revision for each, in revisit order | ||
| - **AND** it applies a revision only after the user confirms it | ||
|
|
||
| #### Scenario: Coherent change yields no changes | ||
|
|
||
| - **WHEN** audit mode finds no drifted artifacts, no structural gaps, and no cross-artifact incoherence | ||
| - **THEN** the skill reports the change as coherent and makes no edits | ||
|
|
||
| ### Requirement: User-Confirmed Incremental Application | ||
|
|
||
| The `/opsx:update` skill SHALL propose each artifact revision and apply it only after user confirmation, re-checking coherence after each applied change. | ||
|
|
||
| #### Scenario: Confirm before writing | ||
|
|
||
| - **WHEN** the skill has a proposed revision for an artifact | ||
| - **THEN** it shows the user what it intends to change and why before writing | ||
| - **AND** it writes only after the user confirms | ||
|
|
||
| #### Scenario: Intent change is redirected to a new change | ||
|
|
||
| - **WHEN** the requested revision changes the intent of the change rather than refining it (per the "Update vs. Start Fresh" heuristic) | ||
| - **THEN** the skill recommends starting a new change (`/opsx:new`) instead of mutating the existing proposal into different work | ||
|
|
||
| #### Scenario: Records the drift baseline after an applied edit | ||
|
|
||
| - **WHEN** the skill has applied and confirmed a revision to an artifact | ||
| - **THEN** it records that artifact's drift baseline via the CLI's dedicated record operation (not by computing digests itself, and not via read-only `status`) | ||
| - **AND** subsequent audits report that artifact as no longer drifted until an upstream changes again |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Align missing-output digest representation with CLI spec.
The artifact-graph spec says "no digest is reported" (line 78) while the CLI spec allows "omits
digest(or reports it as null)" (line 35). Choose one representation and apply it consistently across both specs to avoid implementation ambiguity.Additionally, the tasks.md (2.1) mentions digest scheme prefixes (e.g.,
sha256-relpath-v1:) for forward-compatibility, but this requirement does not mention scheme tags. Consider adding a requirement that digests include a scheme/version prefix so that future canonicalization changes are detectable rather than silently mis-compared.🤖 Prompt for AI Agents