v1.1 Status: Released · 2026-05-12 · Apache 2.0
ChangeSpec 1.1 Specification
A standard event format for communicating software changes from producers to consumers.
Abstract #
ChangeSpec defines a standard event format for communicating software changes from producers (vendors, library maintainers, service operators) to consumers (developers, agents, compliance teams). A ChangeSpec event is a self-describing JSON object with a fixed set of required fields and a rich set of optional fields covering severity, affected version ranges, migration guidance, and source attribution.
This document specifies:
- The core event structure and field semantics
- The category taxonomy
- The severity taxonomy
- Vendor identifier format
- Source attribution model
- Signing and verification for publisher-verified events
- Envelope format and CloudEvents compatibility
- Transport bindings: HTTPS webhook, MCP, RSS/Atom, polling API
- Extension field convention
- Backward compatibility rules
Conformance #
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
A conforming event is a JSON object that validates against the ChangeSpec JSON Schema (schema.json) included in this repository.
A conforming producer generates events that are conforming events.
A conforming consumer accepts conforming events and ignores unknown fields (including extension fields) without error.
1. Core Event Structure #
A ChangeSpec event is a JSON object. All field names are lowercase with underscores.
1.1 Required Fields #
| Field | Type | Description |
|---|---|---|
specversion |
string | Must be "1.1". ("1.0" is accepted by conforming consumers for backward compatibility.) |
id |
string | Globally unique event identifier. Producers SHOULD use the format cs_ followed by a ULID or UUIDv4. Must be stable - the same logical event must always have the same id. |
vendor_id |
string | Identifies the vendor or package. See Section 3. |
category |
string | Change category. One of the values defined in Section 4. |
severity |
string | Change severity. One of the values defined in Section 5. |
title |
string | Short, human-readable change title. Maximum 200 characters. Plain text; no markdown. |
summary |
string | 1-5 sentence plain-English description of what changed and what the impact is. No markdown. Maximum 2000 characters. |
published_at |
string | RFC 3339 timestamp when this event was published. Example: "2026-04-10T14:00:00Z". |
source_type |
string | Indicates how this event was produced. One of: publisher_verified, crawled, community. See Section 6. |
1.2 Optional Fields #
| Field | Type | Description |
|---|---|---|
effective_date |
string | RFC 3339 full-date when the change takes effect. |
source_url |
string | URL of the primary source document for this event. |
affected_versions |
string | Semver range string (npm semver syntax) describing which versions are affected. |
fixed_in_version |
string | Exact semver version where this issue is resolved. |
migration_hint |
string | One or two sentences describing the immediate action a consumer should take. Maximum 500 characters. |
migration_url |
string | URL of a migration guide or detailed remediation instructions. |
confidence_score |
number | Float in [0.0, 1.0]. Producer confidence in the classification. 1.0 for publisher-verified events. |
sunset_date |
string | RFC 3339 full-date. For deprecations: when the deprecated feature is removed. |
cve_id |
string | CVE identifier in format CVE-YYYY-NNNNN. For security events only. |
cvss_score |
number | CVSS base score (0.0-10.0). For security events only. |
cvss_vector |
string | CVSS vector string. |
affected_systems |
array of string | Named systems or products within the vendor that are affected. |
affected_sections |
array of string | Document section headers affected (relevant for TOS/DPA changes). |
action_required |
boolean | Whether consumers must take action. true for breaking changes and critical security events. |
recommended_reviewers |
array of string | Suggested reviewer roles: engineering, security, legal, compliance, procurement. |
tags |
array of string | Freeform tags for filtering. Maximum 20 tags, each maximum 50 characters. |
do_not_install |
boolean | When true, tooling MUST NOT install the affected versions. Only valid when category is retraction. Added in v1.1. |
provenance_invalidated |
boolean | When true, signals that build attestations (SLSA, Sigstore) for the affected versions are valid but from a compromised pipeline and MUST NOT be trusted. Added in v1.1. |
last_known_good_version |
string | Exact semver version of the last version the vendor considers safe to install. Provided by the vendor in retraction events. Added in v1.1. |
retraction_reason |
string | Machine-readable reason code for a retraction. One of: supply_chain_compromise, critical_defect, accidental_publish, security_vulnerability. Added in v1.1. |
signature |
object | Ed25519 signature block. Present only on publisher_verified events. See Section 7. |
ext:* |
any | Extension fields. See Section 10. |
1.3 Field Constraints #
- All string fields containing URLs MUST be valid absolute URIs (RFC 3986).
published_atMUST be a valid RFC 3339 datetime string.effective_dateandsunset_date, when present, MUST be valid RFC 3339 full-date strings (YYYY-MM-DD).idMUST be unique across all events from a given producer.titleMUST NOT contain newlines.summaryMUST be plain text. Producers MUST NOT include markdown syntax, HTML, or other markup.
2. Minimal Conforming Event #
The smallest valid ChangeSpec event:
{
"specversion": "1.1",
"id": "cs_01HXYZ1234ABCD",
"vendor_id": "acme",
"category": "informational",
"severity": "informational",
"title": "Documentation typo fix in authentication section",
"summary": "Corrected a typo in the authentication section of the developer documentation. No behavior change.",
"published_at": "2026-04-10T14:00:00Z",
"source_type": "crawled"
}
3. Vendor Identifier Format #
The vendor_id field identifies the vendor or package. It uses a namespaced format to avoid collisions between ecosystems.
3.1 Format Rules
A vendor_id MUST match the pattern:
vendor_id = [namespace ":"] slug
namespace = 1*( ALPHA / DIGIT )
slug = 1*( ALPHA / DIGIT / "-" / "_" )
3.2 Namespace Conventions
| Namespace | Meaning | Example |
|---|---|---|
| (none) | Named company or service, globally unique | stripe, anthropic, github |
npm | npm registry package | npm:lodash |
pypi | Python Package Index | pypi:requests |
cargo | Rust crates.io | cargo:serde |
gem | RubyGems | gem:rails |
maven | Maven Central | maven:org.springframework:spring-core |
go | Go module | go:golang.org/x/net |
docker | Docker Hub image | docker:nginx |
gh | GitHub repository | gh:facebook/react |
3.3 Registry
Vendor IDs without a namespace represent named services and companies. The ChangeSpec registry (maintained by Roboticforce Inc.) is the canonical source for no-namespace vendor IDs. Registry submissions are open.
4. Category Taxonomy #
The category field classifies what kind of change this event represents. Categories drive routing and filtering in consuming systems.
| Value | Description |
|---|---|
api_breaking | A change to a public API, SDK, or service interface that is not backward compatible. Callers that do not update their code will break. |
api_deprecation | A feature, endpoint, parameter, or behavior is deprecated and will be removed in a future version. Not immediately breaking. Carries a sunset date. |
security | A security vulnerability, patch, or advisory. Use for CVEs, credential exposure risks, and authentication changes that affect security posture. |
data_handling | A change to how user or customer data is stored, processed, shared, or retained. Covers DPA changes, subprocessor additions or removals, data residency changes, and retention policy updates. |
liability | A change to terms of service, SLA, indemnification clauses, limitation of liability, or warranty terms. |
pricing | A change to pricing, billing, plan limits, free tier entitlements, or trial terms. |
tos | A change to terms of service, acceptable use policy, or community guidelines not covered by liability. |
retraction | A signed vendor declaration that one or more versions should not be installed or used. Indicates a supply-chain compromise, critical defect, or other condition making the package unsafe. Carries do_not_install, last_known_good_version, and optionally provenance_invalidated. Added in v1.1. |
cosmetic | A change to documentation, UI text, marketing copy, or visual design. No functional impact. |
informational | A change that does not fit other categories and requires no action. |
4.1 Category Selection Guidance
Categories are mutually exclusive. A single event has one category. When a change fits multiple categories, use the most specific or highest-impact category:
- A DPA update that also constitutes a TOS change: use
data_handling - A security patch that also breaks an API: use
security - A pricing change that is also a TOS update: use
pricing - A new subprocessor announced in a blog post: use
data_handling
5. Severity Taxonomy #
The severity field communicates urgency and potential impact.
| Value | Description |
|---|---|
critical | Immediate action required. Examples: actively exploited vulnerability (CVSS >= 9.0), breaking change already in production with no migration path, data breach notification. |
high | Action required within a short timeframe (days to weeks). Examples: breaking API change with migration path, CVSS 7.0-8.9 vulnerability, major pricing increase with short notice. |
medium | Action required before a future deadline. Examples: deprecation with a 6-month sunset, CVSS 4.0-6.9 vulnerability, subprocessor change requiring DPA review. |
low | Advisory. No immediate action required. Examples: long-horizon deprecations, minor pricing restructuring with no net increase, informational TOS clarification. |
informational | No action required. Purely informational. Examples: documentation improvements, minor wording changes, cosmetic updates. |
5.1 Severity and Category Relationship
Recommended pairings (producers MAY deviate when warranted):
| Category | Typical Severity Range |
|---|---|
retraction | critical |
api_breaking | high to critical |
api_deprecation | low to medium |
security | medium to critical |
data_handling | medium to high |
liability | medium to high |
pricing | low to high |
tos | low to medium |
cosmetic | informational |
informational | informational to low |
6. Source Attribution #
The source_type field communicates how this event was produced and how much trust a consumer should place in the classification.
| Value | Description |
|---|---|
publisher_verified | The vendor that owns the vendor_id pushed this event directly through a publisher API. Eligible for signing (see Section 7). |
crawled | The event was generated by an automated system that detected a change. Classification was performed by AI or automated rules. confidence_score SHOULD be set. |
community | The event was submitted by a community member who is not the vendor. Subject to moderation. confidence_score SHOULD be set lower than for crawled unless independently verified. |
6.1 Confidence Score
The confidence_score field is a float in [0.0, 1.0]:
publisher_verifiedevents: SHOULD be1.0crawledevents: SHOULD reflect AI model confidence. Values below0.7indicate uncertain classification and SHOULD trigger human review.communityevents: producers SHOULD default to0.6unless verification has been performed.
7. Signing and Verification #
Publisher-verified events MAY be signed using Ed25519 to allow consumers to verify authenticity.
7.1 Why Ed25519
Ed25519 provides compact signatures (64 bytes), fast verification, and is not vulnerable to weak random number generation attacks that affect ECDSA. It is implemented in the Go standard library (crypto/ed25519), Node.js (crypto), and Python (cryptography package).
7.2 Signature Object
{
"signature": {
"alg": "ed25519",
"key_id": "stripe-2026-01",
"value": "<base64url-encoded 64-byte signature>",
"signed_fields": ["id", "vendor_id", "category", "severity", "title", "summary", "published_at"]
}
}
7.3 Signature Input Construction
The signature is computed over a canonical byte string:
- For each field name in
signed_fields, in the order listed:- Append the field name as UTF-8 bytes
- Append a newline character (
\n) - Append the field value serialized as its JSON value
- Append a newline character (
\n)
- Sign the resulting byte string with Ed25519.
7.4 Key Distribution
Vendors publish their Ed25519 public keys at a well-known URL:
https://{vendor-domain}/.well-known/changespec-keys.json
{
"keys": [
{
"key_id": "stripe-2026-01",
"alg": "ed25519",
"public_key": "<base64url-encoded 32-byte public key>",
"valid_from": "2026-01-01",
"valid_until": "2027-01-01"
}
]
}
7.5 Verification Steps
A conforming consumer verifying a signed event MUST:
- Check that
source_typeispublisher_verified. - Retrieve the public key identified by
signature.key_id. - Check that the current time is within the key's
valid_from/valid_untilwindow. - Reconstruct the signature input from
signed_fieldsand their values. - Verify the Ed25519 signature.
- Reject the event if verification fails.
7.6 Key Separation from CI (v1.1) #
Signing keys used for publisher_verified events, and especially for retraction events, MUST be stored and accessed outside the CI/CD pipeline that builds and publishes the package. The signing step MUST be performed in a context where CI credentials do not have access to the private key material.
This requirement exists because build provenance (SLSA, Sigstore) attests that a package was built in a specific CI environment - it does not attest vendor intent. If signing keys are accessible from within the same CI context, a compromised pipeline can produce both valid attestations and valid ChangeSpec signatures. Keys held separately are the orthogonal signal that provenance alone cannot provide.
Acceptable key storage patterns include: hardware security modules (HSM), secrets managers with CI access blocked by policy, or manual out-of-band signing workflows for retraction events.
8. Envelope Format #
8.1 Standalone Format
The default transport format is a standalone JSON object. The event fields defined in this spec are the top-level keys.
8.2 CloudEvents Envelope
ChangeSpec events MAY be transported inside a CloudEvents 1.0 envelope.
| CloudEvents Field | Value |
|---|---|
specversion | "1.0" (CloudEvents version) |
id | The ChangeSpec event id |
source | "https://changespec.com/vendors/{vendor_id}" |
type | "com.changespec.change.v1" |
datacontenttype | "application/json" |
time | The ChangeSpec published_at value |
data | The complete ChangeSpec event object |
9. Transport Bindings #
ChangeSpec defines four transport bindings. Platforms are free to implement any or all of them.
9.1 HTTPS POST Webhook #
The event is delivered as an HTTP POST request with:
Content-Type: application/json- Body: standalone ChangeSpec event JSON
Webhook security follows the Standard Webhooks specification (standardwebhooks.com).
9.2 MCP (Model Context Protocol) #
ChangeSpec events are returned by MCP tool calls as JSON objects. Conforming MCP implementations MUST return the standalone ChangeSpec event format in tool responses. Events returned by MCP tools MAY be truncated when context length is a concern; truncation MUST be indicated by setting _truncated: true in the returned object.
9.3 RSS/Atom Feed #
RSS 2.0 field mapping:
| RSS Field | ChangeSpec Source |
|---|---|
<title> | title |
<description> | summary |
<link> | source_url |
<pubDate> | published_at (RFC 822 format) |
<guid> | id |
<category> | category |
The full ChangeSpec event object SHOULD be embedded as a <changespec:event> extension element with namespace xmlns:changespec="https://changespec.com/ns/1.0".
9.4 Polling API #
Platforms providing a polling API MUST return events in the following envelope:
{
"events": [
{ ... ChangeSpec event ... }
],
"next_cursor": "opaque-pagination-token",
"has_more": true
}
10. Extension Fields #
Producers MAY add extension fields using the ext: prefix:
{
"ext:compliance.osfi_b10": true,
"ext:compliance.dora_article": "32",
"ext:internal.ticket_id": "ENG-4521",
"ext:risk.vendor_tier": 1
}
Extension field namespaces SHOULD be registered to avoid conflicts. A public namespace registry is planned at changespec.com/extensions. Conforming consumers MUST ignore unknown extension fields without error.
11. Backward Compatibility Rules #
11.1 Producer Rules
- Producers MUST set
specversionto the version of this spec they conform to. - Producers MUST NOT remove required fields.
- Producers MAY add extension fields at any time.
11.2 Consumer Rules
- Consumers MUST ignore fields they do not recognize, including extension fields.
- Consumers MUST NOT reject events solely because they contain unknown fields.
11.3 Spec Evolution Rules
- Patch releases (1.0.1): Clarifications only. No field additions, removals, or semantic changes.
- Minor releases (1.1, 1.2): May add optional fields. May extend enum values in
categoryandseverity. Existing values MUST NOT be removed or redefined. - Major releases (2.0): May change required fields. Require a formal deprecation period of at least 12 months.
12. Security Considerations #
12.1 Input Validation
Consumers MUST validate all incoming events against the JSON Schema before processing. Malformed events MUST be rejected before any field values are processed.
12.2 URL Fields
All URL fields (source_url, migration_url) are untrusted input. Consumers that fetch content from these URLs MUST use a safelist of permitted URL schemes, implement timeouts and size limits, and not render fetched content without sanitization.
12.3 Signature Verification
Consumers that accept publisher_verified events from untrusted transport layers SHOULD verify signatures. Consumers receiving events from a trusted platform that has already performed verification MAY omit re-verification.
12.4 Replay Attacks
The id field is a stable identifier. Consumers SHOULD implement idempotency using id to prevent processing duplicate deliveries.
Appendix A: Field Quick Reference #
Required fields: specversion, id, vendor_id, category, severity, title, summary, published_at, source_type
Security fields: cve_id, cvss_score, cvss_vector, fixed_in_version
Version fields: affected_versions, fixed_in_version
Temporal fields: published_at, effective_date, sunset_date
Guidance fields: migration_hint, migration_url, action_required, recommended_reviewers
Attribution fields: source_url, source_type, confidence_score
Signing fields: signature
Appendix B: MIME Type #
The MIME type for a ChangeSpec event document is:
application/vnd.changespec+json
When serving events over HTTP, producers SHOULD set Content-Type: application/vnd.changespec+json.
Appendix C: Normative References #
- RFC 2119: Key words for use in RFCs to Indicate Requirement Levels
- RFC 3339: Date and Time on the Internet: Timestamps
- RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
- RFC 8032: Ed25519
- JSON Schema draft 2020-12: json-schema.org
- CloudEvents 1.0: github.com/cloudevents/spec
- Semantic Versioning 2.0.0: semver.org
- Standard Webhooks: standardwebhooks.com
- CVSS 3.1: first.org/cvss