Skip to content

Marketplace (Planned)

The marketplace is a registry for discovering, installing, and updating device-type libraries — the reusable templates described in Type System. It is the distribution layer above the bundle format: where Creating Types covers authoring a .cspkg, this page covers how a published bundle is resolved per tenant and customised through overrides.

A published library lands in the platform’s global type catalog; organisations commission instances against a pinned (typeId, version) and customise through overrides — never per-org forks. Availability never depends on a hardware identity. The hosted catalogue that will front this — its address and routing — is part of the distribution model still to be announced.

The marketplace is deliberately constrained to device-type templates — the one template kind that is actually built. Templates for processes, alarm sets, dashboards, electrical models, mission models, and scene graphs are explicitly out of scope here; that boundary is a deferral marker, not a framework. The working presumption is that non-device-type templates will eventually reuse the same materialiser machinery, but nothing is locked and nothing is built. For now, “marketplace” means device-type libraries.

A library is a versioned package of related device types, distributed as a bundle:

ArtefactContents
.cspkgA library — one or more device types plus shared assets

A .cspkg carries the device-type definition as authored YAML — manifest.yaml, alarms/alarms.yaml, commands/commands.yaml, optional simulation.yaml, and components/*.yaml. See Type System for the bundle layout, Tags for the tag schema, and Alarms & Commands for those manifests.

Resolution is a pure function:

(masterBundle, version, overrides[]) → resolvedTypeDefinition
  • masterBundle — the canonical device-type package as published (e.g. consystence.pump.centrifugal).
  • version — the pinned semver of the master bundle (e.g. 1.2.0).
  • overrides[] — an ordered list of per-tenant JSON Patch operations layered on the master.

The output, resolvedTypeDefinition, is the fully materialised type — tags, states, alarms, commands, simulation profile, and faceplate component tree, with all binding expressions ({tags.X}, {instance.X}, …) preserved for the renderer to resolve at render time. Because the function is deterministic (same inputs → same output), its results are cached, keyed by (bundleId, version, overridesHash) where overridesHash is a SHA-256 of the normalised override set. Caching is what makes many instances of one type cheap: a tenant’s hundred pump-* instances all reuse the single materialised definition.

The materialiser works on JSON internally. Authors write YAML in the .cspkg; conversion to JSON happens at bundle ingest (upload or load-from-disk), and JSON is the representation throughout the materialiser, cache, override storage, and wire format. The author experience is unchanged — YAML in, JSON hidden.

This is a two-stage pipeline. The materialiser produces a template definition; the renderer (see Type System and the server-driven UI) then binds that definition to a specific instance and live state to produce the semantic UI tree. The renderer transforms; the materialiser stays instance-unaware.

flowchart LR
    B["Master bundle .cspkg<br/>consystence.pump.centrifugal"] --> M
    V["Pinned version<br/>1.2.0"] --> M
    O["Tenant overrides[]<br/>JSON Patch RFC 6902"] --> M
    M["Materialiser<br/>pure + cached by<br/>bundleId,version,overridesHash"] --> R["resolvedTypeDefinition<br/>tags + states + alarms<br/>+ commands + faceplate"]
    R --> RN["Renderer<br/>binds instance + live state"]
    RN --> UI["Semantic UI tree<br/>per instance"]

Overrides let a tenant customise a published type without forking it — a site sets a low-flow threshold, a partner relabels faceplate strings into local operator vocabulary, an engineer adds an alarm after a safety review.

  • Paths use JSON Pointer (RFC 6901) — e.g. /alarms/1/threshold, /alarms/- (append), /faceplate/children/0/label.
  • Operations use JSON Patch (RFC 6902), applied in order.
  • Conflicts resolve last-wins by default (JSON Patch semantics). Whether production moves to error-on-conflict is a deferred decision, not yet locked.
  • Isolation is by construction. Each tenant’s override set is a distinct cache key, so one organisation’s overrides cannot leak into another’s — both resolve independently against the same master bundle.

When a master bundle is republished (e.g. 1.2.0 → 1.3.0), a tenant’s overrides reapply against the new version. If an override targets a path the new structure no longer has, the planned default is to fail at materialise time so the broken intent surfaces explicitly rather than being silently dropped — though the exact invalidation policy (error / warn-and-skip / smart-migrate) and content-addressed (predicate) paths are deferred markers, not yet locked.

Consystence’s own first-party device-type libraries are governed by exactly the same rules as any third-party integrator’s library. The goal state is versioned .cspkg bundles resolved through the same materialiser; today the first-party libraries load from unpacked YAML directories on disk at server startup into a platform-wide global registry. (The device-type libraries and the control blocks beneath them together form the Consystence Standard Library; the control-block library is maintained as a single behaviour master with published conformance vectors, and is distributed to control targets through the control-code pipeline rather than the type registry.) What holds regardless is the data rule: a device type’s full behaviour — control/routing model, state encoding, alarms, commands, simulation, components — lives in the bundle manifest as data, never in platform code.

The practical test: any typeId-keyed branch, switch, or allowlist in platform code is a violation, because it would make a library update a code release — a shortcut a third party could never use. The consequence for the marketplace is the load-bearing promise: publishing or updating a library, first-party or third-party, is a pure data/package operation and never requires a Consystence release.

The publishing flow and the commercial model for paid libraries are to be announced — how libraries are submitted, reviewed, and priced is a future decision, and no publishing API exists yet. Whether an organisation may install or publish will be governed by its rolesowner, admin, member — the same role model the rest of the platform uses.

Marketplace and registry requests authenticate through the platform’s standard schemes (see Auth Model):

  • CIAM Bearer — an Entra External ID token from id.consystence.com, for interactive users.
  • X-Api-Key — a tenant key (prefix csk_) minted via the admin API, for automation; see API Keys.

There is no separate marketplace credential. Once endpoints are published they will appear in the rendered OpenAPI at API Reference.

CapabilityState
Materialiser (bundle, version, overrides[]) → resolvedTypeDefinitionSpecified; validated; deferred to first production surface
JSON Pointer / JSON Patch override pathsSpecified; conflict + invalidation defaults not yet locked
Per-tenant override isolationBy construction (distinct cache key)
Hosted cataloguePlanned
Publishing flow + authoring UIPlanned
Commercial model for paid librariesTo be announced
Non-device-type templatesOut of scope (deferred)