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 device type, this page covers how a published bundle is resolved per tenant and customised through overrides.
Where it lives
Section titled “Where it lives”A published library lands in the platform’s global type catalogue; 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.
Scope: device types only
Section titled “Scope: device types only”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.
Bundles and libraries
Section titled “Bundles and libraries”A library is a versioned package of related device types, distributed as a bundle:
| Artefact | Contents |
|---|---|
.cspkg | A 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.
The materialiser
Section titled “The materialiser”Resolution is a pure function:
(masterBundle, version, overrides[]) → resolvedTypeDefinitionmasterBundle— 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"]
Per-tenant override lifecycle
Section titled “Per-tenant override lifecycle”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.
Goal: no privileged first-party library
Section titled “Goal: no privileged first-party library”Consystence’s own first-party device-type libraries are meant to follow 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: ControlLogix blocks are checked against its test vectors; PLCnext has a generated runtime program built from the same source, run on a virtual PLCnext only and checked with live tests, with no conformance replay and per-block vector replay on PLCnext planned; and the library is distributed to control targets through the control-code pipeline rather than the type registry.) The design rule is the data rule: a device type’s full behaviour — control/routing model, state encoding, alarms, commands, simulation, components — belongs in the bundle manifest as data, not in platform code. The rule is partly in place today: some platform features, such as KPI roles, simulation wiring and code generation, still recognise specific first-party device types, and moving that behaviour into the manifests is ongoing work.
The practical test: any typeId-keyed branch, switch, or allowlist in platform code breaks the rule, because it would make a library update a code release — a shortcut a third party could never use. The goal for the marketplace follows: publishing or updating a library, first-party or third-party, should be a pure data/package operation that never needs a Consystence release. Today the first-party libraries ship with the platform, so updating them still means a platform release.
Publishing and commercial model
Section titled “Publishing and commercial model”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 roles — owner, admin, member — the same role model the rest of the platform uses.
Authentication
Section titled “Authentication”There are no marketplace or registry endpoints yet, and no separate marketplace credential. The platform’s API accepts these credentials (see Authentication, which also covers site-PIN sign-in on a site server, and Auth Model):
- Organisation sign-in — a Bearer token from Entra External ID at
id.consystence.com, for people. - Tenant API key — sent in the
X-Api-Keyheader (prefixcsk_); a key is read-only unless created as an operator key. See API Keys.
Once marketplace endpoints are published they will appear in the rendered OpenAPI at API Reference.
Status
Section titled “Status”| Capability | State |
|---|---|
Materialiser (bundle, version, overrides[]) → resolvedTypeDefinition | Specified; validated; deferred to first production surface |
| JSON Pointer / JSON Patch override paths | Specified; conflict + invalidation defaults not yet locked |
| Per-tenant override isolation | By construction (distinct cache key) |
| Hosted catalogue | Planned |
| Publishing flow + authoring UI | Planned |
| Commercial model for paid libraries | To be announced |
| Non-device-type templates | Out of scope (deferred) |
See also
Section titled “See also”- Type System — bundle layout and the type/instance model
- Creating Types — authoring a device type
- Tags · Alarms & Commands — manifest detail
- Licensing — tiers, SKU pools for installs, entitlement
- Auth Model · API Keys — request authentication