DRAFT

WCP Portability Protocol

WCPP defines how WCP-based dashboard setups are bundled, transported, and reconstructed on a different machine. Where WCP handles runtime communication between widget and host, WCPP handles the packaging and distribution of those widget setups.

Two-layer model

WCP — runtime protocol. Defines widget endpoints, postMessage communication, and the container block. Like HTTP for widgets.

WCPP — portability protocol. Defines the .wcp* file family, format schemas, and distribution via Docker Hub. Like npm for widget setups.

Draft specification. WCPP 1.0 is under active development. Field names, format versions, and structural decisions are subject to change before the final 1.0 release. The reference implementation is the Penrith Beacon® WCP Dashboard application suite — the Electron-based host platform against which all WCP widgets and file formats are developed and tested.

What problem WCPP solves

A WCP dashboard orchestration is a self-contained snapshot: pinned widgets, layout, theme references, and configuration. Moving that setup from one machine to another requires moving not just the layout but also the widget containers that power it, and the themes that style it — none of which are in the layout file itself.

WCPP solves this by defining a family of portable file formats that bundle all of these concerns together. A .wcpa application package, for example, includes the orchestration layout, a snapshot of its theme, and a widget inventory with the Docker image details needed to provision the containers on any WCPP-conformant machine.

End-to-end portability story
Developer creates an orchestration → exports as .wcpa → shares the file → recipient imports it on any WCPP-conformant dashboard → Bonjour reads the widget inventory, pulls images from Docker Hub, provisions containers → the orchestration just works.

Relationship to WCP

WCPP depends on WCP 2.0.0: it references the WCP container block, widget manifests (/widget/wcp), and the Bonjour service. WCP does not depend on WCPP — they are independent, complementary layers in the same ecosystem.

ProtocolScopeSpec
WCP Runtime: widget↔host communication, endpoints, postMessage, container block widgetcontextprotocol.com
WCPP Portability: file formats, Docker distribution, Bonjour import agent wcpp.widgetcontextprotocol.com

Both protocols are part of the broader WCP ecosystem, designed and maintained by Penrith Beacon as open standards for local-first dashboard widget communication and distribution.

The .wcp* Format Family

All four WCPP formats are ZIP archives. Each contains a manifest.json and a README.md at the archive root. Format-specific content varies.

ExtensionFull NameContentsPrimary Use
.wcpo WCP Orchestration Package orchestrations/{id}.json, optional icons/ Share one or more orchestrations
.wcpt WCP Theme Package themes.json Share a collection of themes
.wcpx WCP Distribution Envelope Zero or more .wcpa, .wcpo, .wcpt sub-packages Distribute a complete WCP setup — apps, orchestrations, and themes in one bundle
.wcpa WCP Application Package orchestration.json, themes.json, widgets.json, optional icon.png Share a single launchable application

Choosing the right format:

  • Use .wcpo to share one or more orchestration layouts without themes.
  • Use .wcpt to share a theme collection independently of any orchestration.
  • Use .wcpx to distribute a complete WCP setup — any combination of applications, orchestrations, and themes bundled together. The recipient imports everything in one operation.
  • Use .wcpa for distributing a complete, launchable application — layout, theme, and widget container details bundled in one file.

.wcpo — WCP Orchestration Package

A .wcpo file is a ZIP archive containing one or more orchestration snapshots. It is the base format for sharing dashboard layouts.

Archive structure

manifest.json
README.md
orchestrations/
    {orchestration-id}.json
    ...
icons/                ← present only when image icons exist
    {orchestration-id}.png
widgets.json         ← widget inventory for container provisioning

manifest.json fields

FieldTypeRequiredDescription
formatstringrequiredAlways "wcpo"
formatVersionstringrequiredCurrently "1.1"
idUUID stringrequiredUnique package identifier, generated at export time
namestringrequiredPackage display name
displayNamestringoptionalHuman-readable subtitle
iconstringoptionalEmoji character, or "icons/{id}.png" for image icons
orchestrationCountintegerrequiredNumber of orchestrations in this package
themeRefsstring[]requiredUUIDs of themes referenced by the orchestrations. May be empty.
authorstringoptional
authorEmailstringoptional
authorUrlstringoptional
createdISO 8601requiredExport timestamp
appVersionstringrequiredVersion of the host application that created this package

Notes

  • HTML encoding: In formatVersion "1.1", HTML content in snippet instruments is base64-encoded using a htmlBase64 field (not html). Conformant importers decode it before writing to disk.
  • Instance IDs: The wcpInstanceId field is stripped from all instruments at export time. Importers assign fresh UUIDs — instance IDs are host-local and have no meaning across machines.
  • Icons folder: The icons/ folder is present only when at least one orchestration has an image (data URI) icon. Emoji icons are stored as plain strings directly in the orchestration JSON.
  • Widget inventory: widgets.json is present when the exporting host was able to probe widget URLs at export time. It records Docker image details for each widget URL, enabling container provisioning on import. See Widget Inventory.

.wcpt — WCP Theme Package

A .wcpt file is a ZIP archive containing a named collection of themes. Themes are self-contained sets of CSS custom property values that define the visual appearance of a WCP dashboard.

Archive structure

manifest.json
themes.json
docs/                        ← present when formatVersion is "1.1"
    wcp-theme-collection-<col-slug>-<col-uuid>.md
    wcp-theme-collection-<col-slug>-<col-uuid>.html
    wcp-theme-<theme-slug>-<theme-uuid>.md    ← one per theme
    wcp-theme-<theme-slug>-<theme-uuid>.html
The wcp-theme- prefix makes every extracted file self-describing — the collection-level doc, per-theme docs, and WCAG conformance HTML pages can all be distributed individually without renaming.
formatVersion notes:
"1.0" — manifest + themes.json only.
"1.1" — adds embedded docs/ directory with Markdown and HTML documentation for the collection and each theme. Importers that only consume manifest.json and themes.json remain fully compatible.

manifest.json fields

FieldTypeRequiredDescription
formatstringrequiredAlways "wcpt"
formatVersionstringrequired"1.0" (base) or "1.1" (with embedded docs/ directory)
idUUID stringrequiredUnique collection identifier
collectionNamestringrequiredHuman-readable collection name
descriptionstringoptionalHuman-readable description of the collection
themeCountintegerrequiredNumber of themes in themes.json
authorstringoptional
authorEmailstringoptional
authorUrlstringoptional
collectionUrlstringoptionalURL of the collection's home page
createdISO 8601requiredExport timestamp
docsobjectoptionalIndex of embedded documentation files; presence implies formatVersion: "1.1"
conformancestringoptionalAccessibility conformance level for the entire collection, e.g. "WCAG 2.2:AA"
appVersionstringoptionalVersion of the host application that created this package

docs index structure

When formatVersion is "1.1", the docs field in manifest.json is an object with a collection entry and a themes array. All paths use the wcp-theme- prefix convention:

// manifest.json — docs index (excerpt)
"docs": {
  "collection": {
    "md":   "docs/wcp-theme-collection-penrith-beacon-default-1a71e05b-424f-4dd2-9ba6-072fc4ada57d.md",
    "html": "docs/wcp-theme-collection-penrith-beacon-default-1a71e05b-424f-4dd2-9ba6-072fc4ada57d.html"
  },
  "themes": [
    {
      "uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "name": "Penrith Beacon WCP Light",
      "md":   "docs/wcp-theme-penrith-beacon-wcp-light-b2c3d4e5-f6a7-8901-bcde-f12345678901.md",
      "html": "docs/wcp-theme-penrith-beacon-wcp-light-b2c3d4e5-f6a7-8901-bcde-f12345678901.html"
    }
    // ... one entry per theme
  ]
}

For single-theme .wcpt files, the docs field is a flat object (no collection key):

"docs": {
  "md":   "docs/wcp-theme-penrith-beacon-wcp-light-b2c3d4e5-f6a7-8901-bcde-f12345678901.md",
  "html": "docs/wcp-theme-penrith-beacon-wcp-light-b2c3d4e5-f6a7-8901-bcde-f12345678901.html"
}

themes.json schema

themes.json contains a JSON array of theme objects.

FieldTypeRequiredDescription
idstringrequiredTheme identifier
uuidstringrequiredTheme UUID, used for conflict detection on import
namestringrequiredDisplay name
varsobjectrequiredCSS custom property map: { "--var-name": "value", ... }
variantstringrequired"light", "dark", or "high-contrast"
wcpVersionstringrequiredWCP version this theme targets, e.g. "2.2.1"
descriptionstringoptionalHuman-readable scene or theme description
conformancestringoptionalAccessibility conformance level, e.g. "WCAG 2.2:AA"
collectionIdUUID stringoptionalUUID of the parent collection manifest; omit for standalone themes
authorstringoptionalPer-theme author, overrides package-level author if present
authorEmailstringoptional
authorUrlstringoptional
themeUrlstringoptionalURL of the theme's own web page

Example — Penrith Beacon WCP Light (all 81 tokens)

// themes.json (single theme object — Penrith Beacon WCP Light, canonical default)
{
  "id":          "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "uuid":        "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "name":        "Penrith Beacon WCP Light",
  "variant":     "light",
  "wcpVersion":  "2.2.1",
  "description": "The canonical default light theme for the Penrith Beacon® WCP Dashboard.",
  "conformance": "WCAG 2.2:AA",
  "collectionId":"1a71e05b-424f-4dd2-9ba6-072fc4ada57d",
  "author":      "Anthony Harrison",
  "authorEmail": "widgets@penrithbeacon.com",
  "authorUrl":   "https://harrisonofthenorth.com",
  "themeUrl":    "https://penrithbeacon.com",
  "vars": {
    // — Surfaces —
    "--wcp-color-bg":                    "#ffffff",
    "--wcp-color-surface":               "#f6f8fa",
    "--wcp-color-surface-raised":        "#eaeef2",
    "--wcp-color-surface-sunken":        "#ffffff",
    "--wcp-color-overlay":               "rgba(255,255,255,0.75)",
    // — Borders —
    "--wcp-color-border":                "#d0d7de",
    "--wcp-color-border-strong":         "rgba(31,35,40,0.25)",
    // — Text —
    "--wcp-color-text":                  "#1f2328",
    "--wcp-color-text-muted":            "#636c76",
    "--wcp-color-text-disabled":         "rgba(99,108,118,0.5)",
    "--wcp-color-text-inverse":          "#ffffff",
    "--wcp-color-link":                  "#0969da",
    // — Brand —
    "--wcp-color-primary":               "#8B6914",
    "--wcp-color-primary-dim":           "rgba(139,105,20,0.12)",
    "--wcp-color-primary-on":            "#ffffff",
    // — Status —
    "--wcp-color-success":               "#1a7f37",
    "--wcp-color-success-on":            "#ffffff",
    "--wcp-color-success-surface":       "rgba(26,127,55,0.12)",
    "--wcp-color-warning":               "#9a6700",
    "--wcp-color-warning-on":            "#ffffff",
    "--wcp-color-warning-surface":       "rgba(154,103,0,0.12)",
    "--wcp-color-danger":                "#cf222e",
    "--wcp-color-danger-on":             "#ffffff",
    "--wcp-color-danger-surface":        "rgba(207,34,46,0.12)",
    "--wcp-color-info":                  "#0969da",
    "--wcp-color-info-on":               "#ffffff",
    "--wcp-color-info-surface":          "rgba(9,105,218,0.12)",
    // — Typography —
    "--wcp-font-family":                 "-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif",
    "--wcp-font-mono":                   "ui-monospace,'Cascadia Code','Source Code Pro',Menlo,Consolas,monospace",
    "--wcp-font-size-xs":                "11px",
    "--wcp-font-size-sm":                "12px",
    "--wcp-font-size-md":                "14px",
    "--wcp-font-size-lg":                "16px",
    "--wcp-font-size-xl":                "20px",
    "--wcp-font-size-2xl":               "24px",
    "--wcp-font-size-3xl":               "32px",
    "--wcp-font-weight-normal":          "400",
    "--wcp-font-weight-medium":          "500",
    "--wcp-font-weight-semibold":        "600",
    "--wcp-font-weight-bold":            "700",
    "--wcp-line-height-tight":           "1.2",
    "--wcp-line-height-normal":          "1.5",
    "--wcp-line-height-relaxed":         "1.75",
    // — Spacing —
    "--wcp-space-1":                     "4px",
    "--wcp-space-2":                     "8px",
    "--wcp-space-3":                     "12px",
    "--wcp-space-4":                     "16px",
    "--wcp-space-5":                     "20px",
    "--wcp-space-6":                     "24px",
    "--wcp-space-7":                     "32px",
    "--wcp-space-8":                     "64px",
    // — Shape —
    "--wcp-radius-sm":                   "4px",
    "--wcp-radius-md":                   "8px",
    "--wcp-radius-lg":                   "12px",
    "--wcp-radius-xl":                   "16px",
    "--wcp-radius-round":                "9999px",
    // — Shadow —
    "--wcp-shadow-sm":                   "0 4px 8px rgba(0,0,0,.12)",
    "--wcp-shadow-md":                   "0 4px 12px rgba(0,0,0,.2)",
    "--wcp-shadow-lg":                   "0 8px 24px rgba(0,0,0,.25)",
    "--wcp-shadow-xl":                   "0 16px 40px rgba(0,0,0,.3)",
    // — Motion —
    "--wcp-motion-fast":                 "100ms",
    "--wcp-motion-normal":               "200ms",
    "--wcp-motion-slow":                 "350ms",
    "--wcp-easing-standard":             "ease",
    "--wcp-easing-out":                  "ease-out",
    "--wcp-easing-in":                   "ease-in",
    "--wcp-easing-spring":               "cubic-bezier(0.34,1.56,0.64,1)",
    // — Z-index —
    "--wcp-z-base":                      "0",
    "--wcp-z-raised":                    "10",
    "--wcp-z-dropdown":                  "1000",
    "--wcp-z-sticky":                    "1100",
    "--wcp-z-modal":                     "1200",
    "--wcp-z-toast":                     "1300",
    "--wcp-z-tooltip":                   "1400",
    // — Focus & Touch —
    "--wcp-focus-ring-width":            "2px",
    "--wcp-focus-ring-offset":           "2px",
    "--wcp-focus-ring-color":            "#8B6914",
    "--wcp-touch-target-min":            "44px",
    // — Widget —
    "--wcp-widget-bg":                   "#f6f8fa",
    "--wcp-widget-border":               "#d0d7de",
    "--wcp-widget-radius":               "8px",
    "--wcp-widget-padding":              "16px",
    "--wcp-widget-gap":                  "12px",
    "--wcp-widget-shadow":               "0 4px 8px rgba(0,0,0,.12)"
  }
}

.wcpx — WCP Distribution Envelope

A .wcpx file is a distribution bundle containing zero or more packages of each type: .wcpa application packages, .wcpo orchestration packages, and .wcpt theme packages. It is the intended format for distributing a complete WCP ecosystem setup in a single file — bundling live orchestrations, applications, and archived packages together.

All sub-packages are complete, valid archives in their own right and can be extracted and imported individually if needed.

Archive structure (formatVersion 2.0)

manifest.json
README.md
applications/                ← zero or more .wcpa files
    {orch-id-1}.wcpa
    {orch-id-2}.wcpa
    ...
orchestrations/             ← zero or more .wcpo files
    live-export.wcpo
    {archived-name}.wcpo
    ...
themes/                       ← zero or more .wcpt files
    {theme-pack-1}.wcpt
    ...

At least one sub-package must be present — an empty .wcpx is invalid. Any combination of sub-packages is valid: a bundle of only applications, only themes, or any mix.

manifest.json fields

FieldTypeRequiredDescription
formatstringrequiredAlways "wcpx"
formatVersionstringrequired"2.0" (v2.0 bundle) or "1.1" (legacy flat format)
idUUID stringrequiredUnique package identifier
authorstringoptional
authorEmailstringoptional
authorUrlstringoptional
createdISO 8601requiredExport timestamp
appVersionstringrequiredHost app version
contentsstring[]requiredFlat array of all sub-package paths. Importers dispatch by file extension.

contents field example

{
  "format":        "wcpx",
  "formatVersion": "2.0",
  "contents": [
    "applications/my-app-id.wcpa",
    "applications/another-app-id.wcpa",
    "orchestrations/live-export.wcpo",
    "themes/dark-collection.wcpt"
  ]
}

Import semantics

A conformant importer reads the contents array and processes each entry by its file extension — .wcpa, .wcpo, or .wcpt. All orchestrations and themes from all sub-packages are aggregated into a single conflict-resolution pass before any data is written. Widget inventories from both .wcpa and .wcpo sub-packages are combined to provide container provisioning information in the post-import checklist.

Backwards compatibility: formatVersion "1.1" files use a flat structure with orchestrations.wcpo and themes.wcpt at the archive root. Conformant importers detect the version and handle both formats.

.wcpa — WCP Application Package

A .wcpa file is the richest WCPP format. It bundles a single orchestration as a distributable, launchable application — including its themes, a widget container inventory, and optionally an icon. It is the intended format for sharing complete WCP-based applications.

Archive structure

manifest.json
orchestration.json
themes.json
widgets.json
README.md
icon.png               ← present only when orchestration has an image icon

manifest.json fields

FieldTypeRequiredDescription
formatstringrequiredAlways "wcpa"
formatVersionstringrequiredCurrently "1.0"
idUUID stringrequiredUnique package identifier
namestringrequiredOrchestration name
displayNamestringoptionalHuman-readable subtitle
descriptionstringoptionalDescription of the application
iconstringoptionalEmoji string, or "icon.png" when an image icon is embedded
authorstringoptional
authorEmailstringoptional
authorUrlstringoptional
createdISO 8601requiredExport timestamp
appVersionstringrequiredHost app version
wcpVersionstringrequiredWCP protocol version this application targets
themeRefsstring[]requiredTheme UUIDs referenced by the orchestration. May be empty.

orchestration.json

The full orchestration snapshot, in the same format as a .wcpo orchestration entry. Conformant importers set application: true on the imported orchestration automatically — the flag does not need to be present in the file.

themes.json

Same schema as .wcpt themes.json — a JSON array of theme objects. Includes both explicitly exported themes and any adopted theme snapshot (see Adopted Theme Portability). Duplicate detection by id prevents the same theme appearing twice.

widgets.json

See Widget Inventory — this is the WCPP mechanism for container provisioning. The widgets.json file records Docker image information for every widget URL in the orchestration.

Widget Inventory (widgets.json)

widgets.json is present only in .wcpa files. It records Docker container information for every widget URL referenced in the orchestration, captured at export time by probing each widget's /widget/wcp endpoint.

On import, a WCPP-conformant host uses this inventory to identify which containers need to be provisioned on the receiving machine — and to show the user the exact docker pull commands needed to bring offline widgets online.

Schema

{
  "widgets": [
    {
      "url":         "http://localhost:3741",
      "name":        "WCP Radio",
      "version":     "1.0.0",
      "wcpVersion": "2.0.0",
      "components": ["radio"],
      "container": {
        "image":  "docker.io/penrithbeacon/wcp-widget-radio",
        "tag":    "latest",
        "source": { "type": "registry" }
      }
    }
  ]
}

widgets[] entry fields

FieldTypeDescription
urlstringWidget base URL at time of export
namestringWidget name from the /widget/wcp manifest
versionstringWidget version string
wcpVersionstringWCP protocol version the widget implements
componentsstring[]Component IDs from the widget manifest
container.imagestringFull OCI image path: docker.io/namespace/image
container.tagstringImage tag (typically "latest")
container.source.typestring"registry" · "local" · "dockerfile" · "compose" · "tar"
Widget entries where the URL was unreachable at export time are included with no container field — only the url is recorded. Conformant importers show docker pull commands for entries with source.type: "registry" that are offline on the importing machine.

Adopted Theme Portability

A theme reference (themeRefs) is a UUID pointer to a theme stored in the host dashboard's settings. This works locally, but breaks portability: if the referenced theme is deleted, or does not exist on the receiving machine, the orchestration loses its intended appearance.

WCPP solves this with the adopted theme snapshot. When a user adopts a theme for a specific orchestration, the full CSS vars object is stored directly on the orchestration as adoptedTheme:

// Inside orchestration.json
{
  "id": "my-orchestration",
  "name": "My App",
  "adoptedTheme": {
    "id":   "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "name": "Penrith Beacon WCP Light",
    "vars": {
      "--wcp-color-bg":      "#ffffff",
      "--wcp-color-surface": "#f6f8fa",
      "--wcp-color-primary": "#8B6914",
      "--wcp-color-text":    "#1f2328"
    }
  }
}
The adopted theme snapshot is the WCPP solution to theme portability. It makes theme data self-contained — deletion-proof on both the exporting and importing machine. No UUID lookup required.

Host behaviour

  • On import: if adoptedTheme.vars is present, apply those CSS custom properties when rendering the orchestration — even if the UUID does not exist in local theme settings.
  • On .wcpa export: include the adopted theme in themes.json as a full theme entry alongside any other exported themes. Duplicate detection by id prevents double-inclusion.
The adoptedTheme field is distinct from themeRefs. A themeRef points to a shared theme that can be applied to many orchestrations; an adopted theme is a private snapshot that belongs to exactly one orchestration and travels with it.

Conformance Requirements

A WCPP-conformant host is a WCP dashboard that fully implements the import/export requirements of this specification.

A WCPP-conformant host MUST

  1. 1Import all four formats — .wcpo, .wcpt, .wcpx, .wcpa
  2. 2Detect conflicts on import — orchestration ID or theme UUID already exists on the host
  3. 3Resolve conflicts per-item — the user chooses skip or replace before any data is written
  4. 4Export all four formats
  5. 5Set application: true on any orchestration imported from a .wcpa file
  6. 6Apply adoptedTheme.vars when rendering an orchestration with an adopted theme snapshot
  7. 7Generate fresh wcpInstanceId for all widget instruments on import — instance IDs are host-local and have no meaning across machines
  8. 8Base64-encode HTML content (htmlBase64 field) on .wcpo export; decode on import

A WCPP-conformant host SHOULD

  • Strip wcpInstanceId from all instruments at export time
  • Probe widget URLs during .wcpa export to populate widgets.json container information
  • Present docker pull commands to the user for offline widgets discovered during .wcpa import
  • Require user confirmation before pulling any new Docker image (see Trust Model)
The reference implementation of WCPP is the Penrith Beacon® WCP Dashboard application suite (Design Studio, Kiosk, and Orchestration Manager). Any WCP-conformant dashboard may implement WCPP independently — conformance is defined by this specification, not by any particular implementation.

Docker Hub Distribution

WCPP uses full OCI image paths in the container.image field for unambiguous resolution across registries:

docker.io/penrithbeacon/wcp-widget-radio:latest
└──────── └────────────────────────────  └─────
registry  namespace/image               tag
  • container.source.type: "registry" signals that the image is on Docker Hub or another OCI registry
  • The registry hostname is the first component of the image path (docker.io for Docker Hub)
  • The docker.io prefix is the conventional OCI path form for Docker Hub images

Official widget naming convention

All Penrith Beacon reference widgets follow the pattern:

docker.io/penrithbeacon/wcp-widget-{name}:{tag}

source.type values

ValueMeaning
registryImage is on Docker Hub or another OCI registry. Use the image path to pull.
localImage exists only on the local machine. Cannot be provisioned on a remote machine automatically.
dockerfileImage must be built from source using a Dockerfile.
composeContainer is defined in a Docker Compose file.
tarImage is bundled as a .tar archive.
WCPP does not lock to Docker Hub. Any OCI-compatible registry is valid — the full image path in container.image determines the target registry. Supporting private or alternative registries requires only a host or Bonjour update, not a WCPP spec change.

Bonjour as Import Agent

Bonjour is a companion service to WCPP-conformant hosts. In the WCP runtime spec, Bonjour manages widget container lifecycle — starting, stopping, and health-checking containers that are already registered. In WCPP, Bonjour plays an additional role as an import agent for .wcpa packages.

Provisioning flow

  1. 1User imports a .wcpa file into the host dashboard
  2. 2Host parses widgets.json inventory from the package
  3. 3For each widget with container.source.type: "registry": check whether a container is already running at the url
  4. 4For offline widgets: prompt the user for confirmation, then execute docker pull {image}:{tag}, create and start the container
  5. 5Host wires the imported orchestration to the provisioned containers
  6. 6Host triggers a reload or navigation to show the new orchestration
Scope distinction:
The WCP spec describes Bonjour's role in the runtime lifecycle of containers that are already registered on the host.
WCPP describes Bonjour's role in provisioning new containers from a package import — a one-time setup operation that precedes the runtime lifecycle. Both sections cross-reference each other.

In cases where Bonjour is not available, the host SHOULD still surface the docker pull commands to the user so they can provision the containers manually before launching the imported orchestration.

Trust Model

User confirmation

A WCPP-conformant host MUST require explicit user confirmation before pulling any Docker image from a registry for the first time (per image name). Automatic or silent pulls are not permitted.

Trust boundary

The container.image field in widgets.json is sourced from the widget's own /widget/wcp manifest at export time — it is not inserted by the exporting host. However, importers should treat all image names as untrusted input and surface them visibly to the user before any pull operation.

HTML content

Snippet instrument HTML and masthead ticker HTML are base64-encoded in all WCPP packages. This is a transport encoding for safe JSON serialisation — it is not a security boundary. Conformant hosts decode it on import. Hosts should apply their own content security policies to decoded HTML before rendering.

Future

Image signing and checksum verification are not yet specified in WCPP 1.0. These will be addressed in a future revision.

Private registries: When container.image references a private registry (hostname other than docker.io), the host must ensure the user has appropriate credentials before attempting a pull. WCPP 1.0 does not specify a credential exchange mechanism — this is handled at the host and Bonjour level.

Versioning

WCPP versions independently of WCP. The WCPP version covers the overall specification. Individual format versions (formatVersion in each manifest.json) are incremented per-format when a breaking change is made to that format's schema.

WCPP specification versions

VersionStatusNotes
WCPP 1.0DRAFTCovers the current .wcp* format family. Subject to change.

Format version history

FormatCurrent VersionNotes
.wcpo1.1Added base64 HTML encoding for snippet and ticker content
.wcpt1.1Added variant, wcpVersion, description, conformance, collectionId, themeUrl to theme objects; collectionUrl, description, docs index to manifest; embedded docs/ directory with collection and per-theme Markdown and HTML documentation
.wcpt1.0Initial version
.wcpx2.0Upgraded to multi-package bundle (zero or more of each type); subfolder structure; contents as flat path array
.wcpa1.0Initial version

Settings

About WCP Theme Portability

About .wcpt Theme Files

WCP Portability Specification

WCPP defines how WCP-based dashboard setups are bundled, transported, and reconstructed on a different machine. Where WCP handles runtime communication between widget and host, WCPP handles the packaging and distribution of those widget setups.

Importing a .wcpt file imports a theme using the .wcpt theme portability format defined in that specification.

Full specification: wcpp.widgetcontextprotocol.com

How to Create Your Own Custom Theme

The WCP Widget Theme Studio is a Docker container providing a full theme gallery and custom theme editor for WCP-compliant dashboards. It ships with 15 built-in themes and allows unlimited custom themes — all exportable as .wcpt files ready to import here, or shareable via URL.

Prerequisite: Docker Desktop must be installed before running the Studio. It is free for personal and small-team use:

www.docker.com/products/docker-desktop

The Studio is available free of charge on Docker Hub:

hub.docker.com/r/penrithbeacon/wcp-widget-theme-studio

Quick Start: With Docker Desktop running, open a terminal and paste:

docker run -d \
--name wcp-widget-theme-studio \
-p 3740:3740 \
-v theme_data:/app/data \
-v theme_published:/app/published \
-e CONTAINER_NAME=wcp-widget-theme-studio \
--restart unless-stopped \
docker.io/penrithbeacon/wcp-widget-theme-studio:latest

Once running, open http://localhost:3740 in your browser.

Applying a Theme via URL

The WCP Widget Theme Studio offers a second way to share a custom theme — one that requires no file download or manual import on the recipient’s part. Once a theme has been designed in the Studio, it can be exported directly as a URL parameter that carries the full theme inline.

Where the destination page has no existing query parameters, the Studio generates a complete query string beginning with ? that encodes the entire theme. Appending this to any WCP-aware URL causes the theme to be imported and applied automatically the moment the page loads.

Where the destination page already carries URL parameters, the Studio instead provides a single parameter ready to append with &, so the theme travels alongside existing query data without conflict.

Sharing a Theme via Web Address

What does this do?

Every theme you apply has a name and a set of colour and style choices. This feature lets you copy a special web address that carries your exact theme inside it. When someone else opens that link, the page automatically shows in your theme — without them having to find and apply it themselves.

Which version do I use?

Start of address (? …)

Use this when you are sharing a plain web address, for example https://hyperpolyglot.io. The theme information is added right after the page address, starting with a ?.

Add to existing address (& …)

Use this when the address you are sharing already has a ? somewhere in it. The theme information is added after whatever is already there, using an & to separate it. If you are not sure, look at the address in your browser — if you see a ? after the page name, use this version.

Will it work on any website?

No — only on websites that display the WCP Compliant badge. The badge means the website understands this kind of theme address and knows what to do with it. You will usually find the badge in the page footer.

On other websites the link will still open the page normally — it just will not change the colours.