Gateway Corporate

Developer Docs

Docs/Plugin Contract

Plugin Contract

Authoritative manifest, capability, event, graph, optimization, and delivery rules enforced by the platform.

Updated 2026-04-128 min readdocs/plugin-contract.md

This document describes the public NashTwin plugin contract that is currently safe to rely on when preparing a third-party submission. The validator exported by @nashtwin/common is the source of truth for manifest shape. Where the broader codebase contains internal or staged functionality, this document intentionally limits itself to the supported public submission surface.

For onboarding guidance, see the Plugin SDK. For in-product UI guidance, see Plugin UI Best Practices.

Scope

This contract covers:

  • manifest validation rules
  • public capability names
  • public event subscription names accepted in manifests today
  • graph and optimization extension rules
  • submission lifecycle and review states currently used by the product

This contract does not invent behavior that the runtime does not clearly expose yet. If a field is not fully public or is still staged, the notes below call that out directly.

Manifest

Every plugin must ship a manifest.json file. The platform validates the manifest before storing a submission and validates it again before publishing.

Required fields

Field Type Constraints
id string Reverse-domain format. Must match /^[a-z][a-z0-9]*(\.[a-z][a-z0-9-]*)+$/. Immutable once published.
name string 1 to 100 characters.
description string 1 to 500 characters.
version string Strict semver, for example 1.2.0. No v prefix.
author string 1 to 100 characters.
capabilities string[] At least one value from the capability registry.
events string[] Zero or more values from the public event registry below.

Optional fields

Field Type Constraints
authorUrl string Must be a valid URL if present.
iconUrl string Must be a valid URL if present. Used in Marketplace surfaces.
configSchema object Limited JSON-schema-like object. See Configuration Schema.
webhookEndpoint string Must be a valid URL if present. Required when webhook-handler is declared.
oauthScopes string[] Free-form scope request list subject to manual review. No formal public scope registry is frozen yet.
graphExtension object Declares graph contributions, scopes, residency, retention, and supported event schema versions.
optimizationExtension object Declares optimization runtime and scenario support for strategy plugins.
tags string[] Marketplace discovery tags.

Minimal valid manifest

{
	"id": "com.example.my-plugin",
	"name": "My Plugin",
	"description": "Does something useful in NashTwin.",
	"version": "1.0.0",
	"author": "Example Corp",
	"capabilities": ["digital-twin-extension"],
	"events": ["twin.updated"]
}

Capability Registry

Capability Meaning
crm-enrichment Enriches contacts, deals, or related CRM records with external or derived data.
digital-twin-extension Extends the twin projection and graph-backed business view.
game-theory-strategy Provides strategy, ranking, simulation, or recommendation logic.
ui-component Renders product UI inside NashTwin.
webhook-handler Declares a webhook endpoint in the manifest.

Capability notes

  • webhook-handler requires webhookEndpoint.
  • ui-component should follow Plugin UI Best Practices.
  • game-theory-strategy often pairs with optimizationExtension.
  • digital-twin-extension often pairs with graphExtension.
  • webhook-handler is part of the validated manifest surface, but public third-party delivery transport should be treated as staged unless your integration has been explicitly approved for it.

Event Subscription Registry

These are the event names currently accepted in plugin manifests.

Event type Triggered when
contact.created A new contact is created in CRM.
contact.updated An existing contact changes.
deal.created A new deal is created.
deal.deleted A deal is deleted.
deal.updated An existing deal changes.
outcome.recorded An optimization outcome is recorded for calibration and governance.
pipeline.created A new pipeline is created.
pipeline.updated A pipeline changes.
recommendation.generated A recommendation set is generated by an optimization workflow.
simulation.completed A simulation run completes successfully.
simulation.failed A simulation run fails.
simulation.requested A simulation run is requested.
twin.updated The tenant's digital twin snapshot is recomputed.

Event notes

  • Event delivery uses versioned envelopes with replay-safe identifiers.
  • idempotencyKey is the deduplication key plugin runtimes should honor.
  • Some optimization workflow states exist elsewhere in the codebase as internal platform events, but they are not currently accepted in public third-party manifests. Examples include approval-decision workflow states and denied simulation states.

Event envelope

interface VersionedPluginEvent<T = unknown> {
	eventId: string
	eventType: PluginEventType
	idempotencyKey: string
	payload: T
	schemaVersion: string
	tenantId: string
	timestamp: string
}

Configuration Schema

configSchema allows a plugin to declare install-time configuration fields.

interface PluginConfigSchema {
	type: 'object'
	properties?: Record<string, PluginConfigSchemaProperty>
	required?: string[]
}

interface PluginConfigSchemaProperty {
	type: 'boolean' | 'number' | 'string'
	description?: string
	minimum?: number
	maximum?: number
}

Rules

  • type must be the literal string object.
  • Only scalar property types are supported: boolean, number, and string.
  • minimum and maximum apply only to numeric fields.
  • Nested schema objects and arrays are not currently part of the supported public contract.
  • Use description generously so install and review screens are understandable without source access.

Graph Extension Manifest

Add graphExtension when the plugin contributes graph records or reads graph-backed twin data.

interface PluginGraphExtension {
	contributions: PluginGraphContribution[]
	handledDataClassifications: GraphDataClassification[]
	readScopes: GraphReadScope[]
	residencyGuarantees: GraphResidencyZone[]
	retentionStrategy: PluginGraphRetentionStrategy
	supportedEventSchemaVersions: string[]
	writeScopes: GraphWriteScope[]
}

type PluginGraphContribution =
	| {
			kind: 'node'
			schemaId: string
			displayName: string
			description: string
			layer: GraphDataLayer
			nodeFamily: GraphNodeFamily
			version: string
			dataClassificationTargets: GraphDataClassification[]
		}
	| {
			kind: 'edge'
			schemaId: string
			displayName: string
			description: string
			layer: GraphDataLayer
			edgeType: GraphEdgeType
			version: string
			dataClassificationTargets: GraphDataClassification[]
		}

Graph rules

  • contributions must contain at least one node or edge definition.
  • schemaId must use reverse-domain format.
  • version must be semver.
  • readScopes must contain at least one declared scope.
  • writeScopes may only use non-core write scopes.
  • supportedEventSchemaVersions must contain semver strings.
  • handledDataClassifications must enumerate every classification the runtime may touch.

Public graph read scopes

Scope Meaning
graph.read.governed-core Canonical governed business facts.
graph.read.observation-evidence Observation and evidence records.
graph.read.derived-overlay Derived scores, forecasts, and overlays.
graph.read.compliance Compliance and governance metadata.

Public graph write scopes

Scope Meaning
graph.write.observation-evidence Observation and evidence writes.
graph.write.derived-overlay Derived and overlay writes.

Optimization Extension Manifest

Add optimizationExtension when the plugin exposes strategy or simulation behavior that the product UI and policy controls need to understand.

interface PluginOptimizationExtension {
	advisoryOnly: boolean
	defaultRuntimeMode: 'inline' | 'worker'
	defaultRecommendationCount: number
	maxHorizon: number
	maxRecommendationCount: number
	scenarios?: OptimizationScenarioDefinition[]
	requiresHumanReview: boolean
	supportsApprovalWorkflow: boolean
	supportsExternalWorkers: boolean
	supportsOutcomeCapture: boolean
	supportedGameClasses: OptimizationGameClass[]
	supportedSolverFamilies: OptimizationSolverFamily[]
	supportedTimeScales: OptimizationTimeScale[]
	supportedUtilityTopologies: GameUtilityTopology[]
	timeoutMs: number
}

Scenario shape

interface OptimizationScenarioDefinition {
	description: string
	defaults: {
		gameClass: OptimizationGameClass
		horizon?: number
		timeScale: OptimizationTimeScale
		utilityTopology?: GameUtilityTopology
	}
	id: string
	label: string
	tier: 'basic' | 'advanced' | 'premium'
}

Optimization rules

  • defaultRecommendationCount and maxRecommendationCount must be integers from 1 to 5.
  • maxHorizon must be an integer from 1 to 365.
  • timeoutMs must be an integer from 100 to 300000.
  • Every scenario id must be lowercase kebab-case or dot-separated lowercase segments.
  • Every support array must be non-empty.
  • Use scenario IDs as stable public keys; do not rename them casually after publication.

Delivery and Compatibility

Event schema versioning

  • Public event envelopes currently use schema version 1.0.0.
  • Graph-aware plugins should explicitly declare support through graphExtension.supportedEventSchemaVersions.
  • idempotencyKey is the replay-safe key your runtime should persist or compare before making durable changes.

Webhook transport note

The manifest contract currently validates webhookEndpoint and webhook-handler, but you should not assume automatic external delivery outside approved rollout paths. Treat those fields as a reviewed integration surface rather than an always-on public transport guarantee.

Submission Lifecycle

The current product flow uses the following submission statuses:

Status Meaning
PENDING Submitted and waiting for review.
UNDER_REVIEW An admin has started the review.
REJECTED The manifest was rejected. Review notes may be attached.
PUBLISHED The manifest was revalidated and published into the plugin registry.

Publishing behavior

  • Submission-time validation happens in the Developer Portal before the record is created.
  • Publish-time validation happens again in the admin flow before the plugin is upserted into the registry.
  • Published third-party plugins are stored with source: THIRD_PARTY and status: ACTIVE.
  • A developer cannot keep multiple active review-queue submissions open at once.

Validation Summary

Rule Detail
id format Must match /^[a-z][a-z0-9]*(\.[a-z][a-z0-9-]*)+$/
version format Must match MAJOR.MINOR.PATCH
capabilities Must be non-empty and use only registered names
events Must use only the public event names accepted by the validator
configSchema.type Must be object
graphExtension.contributions Must be non-empty when present
optimizationExtension arrays Must be non-empty when present
webhookEndpoint Required when webhook-handler is declared

Summary

Treat this document as the publishable contract for third-party plugins. If a field is not clearly implemented as public behavior yet, this document does not overstate it. Build from the Plugin SDK, validate against @nashtwin/common, and keep your in-product surfaces aligned with Plugin UI Best Practices.