Skip to content

[RFC]: Refactor of codebase to support capability versioning independent of protocol version #499

Description

@wry-ry

Summary

This is a proposal to refactor the GitHub repository and CI/CD pipeline to support independent versioning for UCP capabilities, extensions, and types and also prepare us for the future of UCP with multiple verticals. By decoupling these from the protocol version, the design enables granular maintenance of the specification. We will cut a new version of the protocol to support these changes.

Motivation

Currently, the UCP GitHub structure and published JSON schemas only support versioning at the protocol level, which creates significant gaps. Specifically, shared types lack individual versions, and built JSON files are restricted to protocol-wide releases. This refactor addresses these limitations to allow capabilities and shared types (like totals.json) to evolve independently of the core protocol.

Goals

UCP defines a versioning scheme that supports versions at the protocol level as well as the capability level. However, the structure of the GitHub, documentation pages, and published JSON schema currently only work for versioning at the protocol level. The updated design should support:

  1. Protocol versions
  2. Capability/extension versions
    1. Capability version to protocol version support mapping can be many-to-many
    2. Types will need versions as specific capability versions may need specific type definitions (e.g. total.json change between v2026-01-23 to v2026-04-08)

While refactoring the GitHub repo to achieve this goal, we need to optimize across a few conflicting considerations

  1. Authoring simplicity - how easy is it for contributors to who are augmenting the protocol to change the documentation
  2. Reader experience - how easy is it for the reader to navigate, search, and understand the documentation structure
  3. Maintenance burden for implementers - how easy is it for platforms and businesses to build and update their implementations of the protocol as it evolves
  4. Infrastructure resilience - how dependent is it on complex setups using external plugins, and how easy is it for devops maintainers to manage the overall documentation and schema build pipeline
  5. Future robustness - how easy is it to accommodate new verticals, backport new changes

Current gaps

  1. Current GitHub structure handles versions using branches, with no versioning below
  2. Spec pages only have a version selector at the protocol level
  3. Built JSON files only support versions at the protocol level (e.g. https://ucp.dev/2026-04-08/schemas/shopping/checkout.json)
  4. Shared types don’t have versions

Proposed changes

Currently the capability version is always the same as the UCP version, but this proposal will decouple them. The version property in the JSON schemas for capability will represent the version of the capability.

Capability version assumptions

We will assume that a capability is only compatible with the most recent spec version equal to or less than the capability version. This is because any change to the spec version would imply a change that affects all capabilities, and so all capability versions will be bumped at the same time.

Example, with UCP-capability version compatibility represented by having the same color boxes:

Image

UCP version bump (2026-05-01 to 2026-07-01):

Image

GitHub source structure

  1. (unchanged) Maintain versioned release branches for the spec version (e.g. release/2026-04-08)
  2. Add version to vertical/types (e.g. shopping/types/2026-04-08)
  3. Represent capability and types versions as subdirs

Proposed structure would look like:

    ├── site/
    │   └── … (everything on ucp.dev not in Specification tab)
    ├── specification/
    │   ├── overview.md
    │   ├── playground.md
    │   ├── … (other core UCP spec documentation)
    │   ├── shopping/
    │   │   ├── checkout/
    │   │   │   ├── 2026-01-23/
    │   │   │   │   ├── checkout.md
    │   │   │   │   ├── checkout-rest.md
    │   │   │   │   └── …
    │   │   │   ├── 2026-04-08/
    │   │   │   │   ├── checkout.md
    │   │   │   │   ├── checkout-rest.md
    │   │   │   │   └── …
    │   │   │   ├── draft/
    │   │   │   └── … (other checkout versions)
    │   │   ├── cart/
    │   │   └── … (other capabilities, extensions)
    │   └── … (other verticals)
    └── source/
        ├── discovery/
        ├── handlers/
        ├── services/
        │   ├── shopping/
        │   │   ├── 2026-01-23/
        │   │   ├── 2026-04-08/
        │   │   └── … (other shopping services versions)
        │   └── … (other verticals)
        ├── schemas/
        │   ├── shopping/
        │   │   ├── checkout/
        │   │   │   ├── 2026-01-23/
        │   │   │   │   ├── checkout.json
        │   │   │   │   └── …
        │   │   │   ├── 2026-04-08/
        │   │   │   │   ├── checkout.json
        │   │   │   │   └── …
        │   │   │   ├── draft/
        │   │   │   └── … (other checkout versions)
        │   │   ├── cart/
        │   │   ├── … (other capabilities)
        │   │   └── types/
        │   │       ├── 2026-01-23/
        │   │       │   ├── totals.json
        │   │       │   └── …
        │   │       ├── 2026-04-08/
        │   │       └── … (other shopping types versions)
        │   └── … (other verticals)
        └── … (other core UCP spec schemas)

CI/CD

Update publishing hooks to handle the new structure above. Ultimately we should have published URLs like:

  1. Documentation
    1. Unversioned structure for pages that are not specifically tied to the spec, e.g. ucp.dev/documentation/core-concepts/
    2. Protocol versioned structure for pages that are tied only to spec version, e.g. ucp.dev/2026-04-08/specification/overview/
    3. Capability and protocol versioned structure for capability documentation, e.g. ucp.dev/2026-04-08/specification/checkout/2026-04-08/overview/
  2. Schemas
    1. We will change the location of the version in the path to better reflect that the version is referencing capability/service/types version instead of UCP version, e.g.:
      1. Capabilities - ucp.dev/schemas/shopping/2026-06-01/checkout.json
      2. Services - ucp.dev/services/shopping/2026-06-01/rest.openapi.json
      3. Types - ucp.dev/schemas/shopping/types/2026-06-01/totals.json

Files

  1. Add version property to all types
  2. Add version to type references (e.g. "$ref": "types/totals.json" → "$ref": "types/2026-04-08/totals.json")

Website

  1. (unchanged) Specification tab will have dropdown selector to choose UCP protocol version
  2. Update Specification navigation to include the versions of each capability and extension in the nav tree that are supported in the selected version of the protocol:
	Specification (2026-04-01 dropdown selected)
	Overview (overview.md)
	Shopping
		Checkout Capability
			Version 2026-05-01 (checkout/2026-05-01/checkout.md)
				Overview
				…
			Version 2026-04-01 (checkout/2026-04-01/checkout.md)
			Draft (checkout/draft/checkout.md)
		Cart Capability
		Catalog Capability
		…
		Reference
		Playground
	Common
		Identity Linking Capability
	Payment Handlers
	Signatures

Backporting changes

Backporting changes will not be allowed across UCP versions, but will be allowed for earlier versions of capabilities within the same UCP version. To do this, you would add the change to the same PR because capability versions will be contained within the same GitHub branch.

Open questions

  1. Services currently have references back to specific capabilities, e.g. in https://ucp.dev/2026-04-08/services/shopping/rest.openapi.json:
"checkout": {
  "$ref": "https://ucp.dev/2026-04-08/schemas/shopping/checkout.json"
},
"checkout_response": {
  "oneOf": [
    {
      "$ref": "https://ucp.dev/2026-04-08/schemas/shopping/checkout.json"
    },
    {
      "$ref": "https://ucp.dev/2026-04-08/schemas/shopping/types/error_response.json"
    }
  ]
},

Suggestion: we can change the specific capability objects to oneOf an array of objects, so the above example could become:

"checkout": {
  "oneOf": [
    {
      "$ref": "https://ucp.dev/2026-04-08/schemas/shopping/checkout.json"
    },
    {
      "$ref": "https://ucp.dev/2026-06-01/schemas/shopping/checkout.json"
    }
  ]
},
"checkout_response": {
  "oneOf": [
    {
      "$ref": "https://ucp.dev/2026-04-08/schemas/shopping/checkout.json"
    },
    {
      "$ref": "https://ucp.dev/2026-06-01/schemas/shopping/checkout.json"
    },
    {
      "$ref": "https://ucp.dev/2026-04-08/schemas/shopping/types/error_response.json"
    },
    {
      "$ref": "https://ucp.dev/2026-06-01/schemas/shopping/types/error_response.json"
    }
  ]
},
  1. https://ucp.dev/latest/specification/overview/#version-requirements states that extensions should declare a requires object that specify protocol and capability versions required for correct operation. However, none of our currently defined extensions declare this. Should we add it?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions