Skip to content

[RFC] Proposal: Repository Refactoring for Multi-Vertical Support #520

Description

@jingyli

Goal: Improve UCP repo structure & developer tooling to facilitate new vertical support.
Status: Proposal (Inviting feedback from Community & Tech Council discussion)
Related: #499, #484

Summary

This proposal outlines the restructuring of the Universal Commerce Protocol (UCP) repositories and schemas to support multiple verticals (such as Food) alongside the existing Shopping specification. It details the phases required to transition from a retail-centric codebase to a modular, vertical-agnostic architecture, enabling UCP to scale as a multi-vertical standard.

Motivation

UCP was started with "Shopping" as the first domain. However, as UCP expands to verticals like Food (menu exploration, cart building, checkout fulfillment), the current repository structure is inefficient.

Currently, retail-specific schemas and documentation are treated as the default "core" of UCP (e.g., checkout and cart specs living at the root of docs/specification/). Furthermore, foundational schemas like signals.json live under shopping specific paths (e.g., source/schemas/shopping/types), and shared transactional concepts like payment instruments are not consolidated as a horizontal layer.

To support multiple verticals without duplication and allow them to evolve independently, we must:

  • Delineate core/common types from vertical-specific types
  • Restructure the directory layout of the main ucp repo (specs and schemas)
  • Align developer tooling (samples, conformance) and SDKs to support vertical-scoped constructs
  • [Not in scope for this RFC] Design a standard process to deal with PR triage and review

This refactor will ensure that UCP remains robust, easy to navigate for readers, and simple to maintain for implementers.

Proposed phases

Phase 1: Restructure specification documentation

Target: ucp

Problem statements

  • Problem 1 (File Structure): The docs/specification/ directory contains retail-specific files at the root (e.g., checkout.md, cart.md).
  • Problem 2 (Rendering Logic): The documentation rendering script (main.py) is tightly coupled to the Shopping vertical layout and assumes a single-vertical structure when it comes to macro definitions. We also need to make reference.md and site navigation bar clearly categorize capabilities under vertical headers (Shopping, Common).

What lands

  • Move existing retail-specific specifications from the root of docs/specification/ to docs/specification/shopping/ (e.g., checkout.md, cart.md, order.md and their -mcp.md/-rest.md bindings).
  • Update main.py to be vertical-agnostic, dynamically generating the documentation site navigation by scanning the vertical subdirectories.
  • Update the UCP website navigation sidebar to group specifications under vertical headers:
Specification
├── Overview (overview.md)
├── Common
│   └── Identity Linking Capability (identity-linking.md)
├── Shopping
│   ├── Cart Capability (shopping/cart.md)
│   │   └── ... (bindings & other extensions)
│   ├── Checkout Capability (shopping/checkout.md)
│   │   ├── ... (bindings & other extensions)
│   │   └── Discount Extension (shopping/discount.md)
│   └── Order Capability (shopping/order.md)
├── Vertical A
│   ├── Cart Capability (vertical_a/cart.md)
│   └── Some Other Vertical A Capability
│       └── ... (bindings & extensions)
├── Payment Handlers
│   └── ...
├── Schema Authoring
└── Reference

Phase 2: Refactor additional common schemas

Target: ucp

Problem statements

  • Problem 1 (Common Types): Foundational types like totals.json, signals.json, and context.json are treated as Shopping-specific types (living specifically under source/schemas/shopping/types/).
  • Problem 2 (Payment Modelling): Payments (instrument modelling) are critical regardless of the vertical, but currently these schemas live under a Shopping specific path instead of being defined as a common horizontal construct.

What lands

  • Complete the migration started in chore: Refactor schema references to common types #436 by moving generic schemas from source/schemas/shopping/types/ to source/schemas/common/types/. This will include files like:
    • totals.json (pricing breakdowns)
    • signals.json (system-derived data)
    • context.json (provisional buyer context)
  • Refactor payment instrument schemas under source/schemas/common/ (or common/types/).
  • Update all references ($ref) in existing schemas to point to the new centralized common schema locations and also fix any references in specification documentation.

Phase 3: Restructure developer tooling repos

Target: samples, conformance

Problem statements:

  • The samples/ and conformance/ repositories are monolithic and assume a retail-only environment. Conformance tests are coupled to shopping mock stores, making it impossible to run conformance tests for other verticals independently.
  • As we add more verticals, maintaining duplicate test runners and boilerplate code across multiple repositories will lead to high maintenance overhead.

What lands

  • Restructure the conformance/ repository into a core test runner and vertical-specific test plugins:
    • conformance/core/: Handles profile discovery (/.well-known/ucp) & negotiation, and error schema assertions.
    • conformance/shopping/, conformance/<vertical>/: Vertical-specific plugins containing semantic test assertions (e.g., validating cart totals calculations or fulfillment logic).
samples/
  └── … (all existing meta-files like LICENSE, .gitignore)
  shopping/
  ├── rest/
  │   └── … (existing files)
  ├── a2a/
  └── └── … (existing files)
  vertical_A/
  ├── mcp/
  │   └── …
  ├── rest/
  └── └── …
conformance/
    ├── … (all existing meta-files like LICENSE, .gitignore)
    ├── core/
    │   └── protocol_test.py (testing profile discovery and negotiation)
    ├── shopping/
    │   ├── checkout_lifecyle_test.py
    │   ├── fulfillment_test.py
    │   └── order_test.py
    │   └── … (other existing files)
    ├── vertical_A/
    │   └── …
    └── vertical_B/
        └── …
  • Update the conformance orchestrator to dynamically load and execute the appropriate vertical plugins based on the capabilities declared in the business's /.well-known/ucp profile (supporting mixed-vertical profiles) or what files have been modified in the draft PR.

Phase 4: Restructure SDK setup

Target: python-sdk, js-sdk(and other languages in the future)

Problem statements

  • SDK code generators output models into a single flat namespace, leading to naming collisions for capabilities that share names across verticals (e.g., Cart in Shopping vs Cart in another vertical).
  • Cross-Namespace Referencing: During generation, vertical-specific models must reference common models (e.g., shopping/checkout.py needs common/totals.py). The generator must resolve these dependencies into correct local imports without creating circular dependencies.

What lands (Assuming Alt A is selected from Open Questions 1)
To align with the recommended Alternative A packaging strategy, we will restructure both SDK repos to support multiple verticals inside a single package release:

Directory & Namespace Restructure

We will transition the source code structure to segregate models by vertical namespace:

  • Python (python-sdk):
    • Restructure src/ucp_sdk/ to introduce namespace submodules:
src/
└── ucp_sdk/
    ├── common/       # ucp.sdk.common.* (Shared models: Totals, Context)
    └── shopping/     # ucp.sdk.shopping.* (Shopping-specific models)
  • JS (js-sdk):
    • Restructure src/ to support subpath exports within the single @ucp-js/sdk package:
src/
├── common/           # exported as @ucp-js/sdk/common
└── shopping/         # exported as @ucp-js/sdk/shopping
  • We will configure the exports field in package.json to enable clean subpath imports for modern JS bundlers without requiring multiple package publishes:
{
  "name": "@ucp-js/sdk",
  "exports": {
    "./common": {
      "types": "./dist/common/index.d.ts",
      "import": "./dist/common/esm/index.js",
      "require": "./dist/common/cjs/index.js"
    },
    "./shopping": {
      "types": "./dist/shopping/index.d.ts",
      "import": "./dist/shopping/esm/index.js",
      "require": "./dist/shopping/cjs/index.js"
    }
  }
}

Generator Toolchain Adaptation

  • Multi-target Generation: Update generate_models.sh in both repositories to invoke the code generator independently for each vertical subdirectory, pointing to the restructured schema paths (e.g. schemas/common/, schemas/shopping/).
  • Reference Resolution: Configure preprocessor scripts (e.g. preprocess_schemas.py for Python SDK) to resolve relative JSON Schema $ref paths (e.g., ../common/types/totals.json) into correct package-relative imports (e.g., from ucp.sdk.common.types import Totals) instead of copying the referenced schema inline or failing.

Implementation Sequence and Suggested PR Titles

Phase Repo Suggested PR title
1 ucp refactor: Restructure docs/specification into vertical subdirectories
1 ucp chore: Make docs rendering logic in main.py vertical-agnostic
2 ucp refactor: Move common schemas to common/types
2 ucp refactor: Move payment schemas to common horizontal constructs
3 samples refactor: Restructure samples repo to support vertical subdirectories
3 conformance refactor: Restructure conformance repo and implement plugin-based architecture for multi-vertical testing
4 python-sdk refactor: Update python-sdk generator to support vertical-scoped packages
4 js-sdk refactor: Update js-sdk generator to support vertical-scoped packages

Non-goals

  • Version & capability negotiation: This proposal does not change how versioning negotiation works, instead it will build on top of the capability versioning proposed in [RFC]: Refactor of codebase to support capability versioning independent of protocol version #499.
  • Developer contribution process: This RFC does not look at process enhancements for PR reviews or escalation channels for DTC.
  • Defining vertical business logic: We are strictly restructuring the repository and schemas for readiness; defining the actual schemas for new verticals is out of scope.

Open questions

1. SDK Package Structure & Distribution

How should the generated SDKs be packaged and distributed to developers? We propose 3 approaches based on well-known industry patterns:

[Recommended] Alternative A: Monolithic Package with Vertical Namespaces

All verticals and common models are shipped in a single package (e.g., pip install ucp-sdk or npm install @ucp-js/sdk), segregated by namespaces.

  • Industry Reference: Stripe SDKs (all services in one package)
  • Pros:
    • Simplicity: Developers only manage a single dependency.
    • Unified Versioning: SDK version maps directly to UCP release version.
    • Frictionless Cross-Vertical Use: Easy to use multiple verticals (e.g., Shopping and a related vertical like Food) in the same application.
  • Cons:
    • Package Size: Developers inherit models for verticals they do not use (primarily a concern in frontend JS environments, though mitigable via tree-shaking).

Alternative B: Modular Packages (Multi-Package Monorepo)

Each vertical and the common core are published as separate packages (e.g., @ucp-js/sdk-common, @ucp-js/sdk-shopping, @ucp-js/sdk-food).

  • Industry Reference: Google Cloud Client Libraries
  • Pros:
    • Minimal Footprint: Developers only install what they need, minimizing dependency bloat.
    • Independent Updates: A bug fix in one vertical's SDK does not require releasing a new version of all other vertical SDKs.
  • Cons:
    • Dependency Management: Higher cognitive load for developers using multiple verticals.
    • Publishing Overhead: Requires complex monorepo tooling (e.g., npm workspaces) and CI/CD pipelines to manage inter-package dependencies and publish N packages.

Alternative C: Core Package + Dynamic Schema Resolution (No Generated Models)

Ship a lightweight "Core" SDK that contains no hardcoded vertical models. Instead, the SDK dynamically downloads or bundles UCP JSON schemas and performs runtime validation/serialization using a generic processor.

  • Industry Reference: AWS Boto3/Botocore (loads service definitions from JSON at runtime)
  • Pros:
    • Zero Code Generation: No need to run generators for different languages; SDK remains thin.
    • Instant Support: Immediately supports new capability versions or verticals just by updating the JSON schema files.
  • Cons:
    • No Compile-time Safety: Developers lose IDE autocomplete and compile-time type checking for vertical entities (e.g., no typed Checkout or Cart classes in IDE).
    • Runtime Performance: Parsing schemas and dynamic validation adds runtime overhead.

2. Extension Rendering & Navigation

How should extensions that are used across capabilities or even verticals (in the case of common extensions like Loyalty) be rendered in the documentation site navigation?

[Recommended] Alternative A: Contextual Nesting (Current State)

Extensions are documented under the capability that leverages them (e.g., Shopping Discounts extension nested under Shopping Checkout capability). If another capability needs it, it is referenced again in the nav.

  • Pros:
    • Contextual: the reader sees the extension in the flow of the capability.
    • Explicit: in the case that there are vertical specific extensions with the same name (e.g., Shopping Fulfillment vs. Food Fulfillment), it's very clear to the user which one is currently being referenced by the capability.
  • Cons:
    • Duplicate entries in the sidebar if multiple capabilities or verticals use the same extension (bloated nav bar).

Alternative B: Centralized "Extensions" Directory

Move all extension documentation to a top-level specification/extensions directory, grouping them by vertical or as common. Individual capability’s md files will have a table listing out all the supported extensions.

  • Pros: Eliminates sidebar duplication; highlights extensions as reusable components.
  • Cons: Disconnects the extension from the core capability documentation, forcing readers to jump between sections to understand the full flow.

Metadata

Metadata

Assignees

Labels

TC reviewReady for TC review

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions