Plugin Development Guide
Version française : ../../fr/guides/plugin-development.md
This guide shows how to build, validate, sign, publish, install, upgrade and remove a plugin. It is for developers
with the developer or tenant_admin role; installing in an environment needs tenant_admin and an approval.
Concept
A manifest of kind Plugin (contracts/v1/plugin-manifest.schema.json) has two formats:
| Format | What it is | Where it goes |
|---|---|---|
pack | A complete Marketplace pack: agents, skills, prompts, MCP servers, connectors, policies, evaluations, tests and docs in English and French. | Published to the Marketplace with enterprise-ai plugin publish, installed through POST /v1/marketplace/installations after a preflight and an approval. POST /v1/plugins refuses it with 422 pack_requires_marketplace. |
oci_plugin (default) | One signed OCI image with declared capabilities, run in a sandbox. | Registered with POST /v1/plugins, installed with POST /v1/plugins/{name}/install. |
A plugin goes through the statuses registered, installing, installed, failed, uninstalled and blocked.
Manifest fields
| Field | Type | Required | Description |
|---|---|---|---|
apiVersion, kind, metadata | yes | enterprise-ai.io/v1, Plugin, name, version (semver), owner. | |
spec.description | string | yes | What the plugin brings. |
spec.capabilities | array | yes | Each item: type (tool, connector, channel, model_adapter, evaluator, ui_extension, policy) and name. |
spec.format | enum | no | oci_plugin or pack. |
spec.artifact | object | oci_plugin | oci_ref, digest (sha256:<64 hex>), media_type. |
spec.signature | object | oci_plugin | digest, cosign_bundle, signer, issued_at. |
spec.sandbox | object | oci_plugin | runtime (gvisor, kata, wasm, none), network (deny_all, egress_allowlist, cluster_only), egress_allowlist, read_only_rootfs, limits. |
spec.permissions, spec.min_platform_version | no | Permissions and minimum platform version of an OCI plugin. | |
spec.license, spec.licenseDeclaration | string, object | pack | SPDX identifier; another licence than MIT or Apache-2.0 needs a declaration (spdx, reason). |
spec.compatibility | object | pack | platform and sdk ranges such as >=1.0.0 <2.0.0. |
spec.requestedPermissions | array | pack | scope, reason, sensitive, classification; the administrator grants a subset. |
spec.dataProtection | object | pack | classification_max, pii, residency. |
spec.approvals | object | pack | install.quorum (1 to 10) and roles. |
spec.docs | object | pack | Paths of the en and fr docs. |
spec.evaluations, spec.tests | array | pack | Evaluation suites (promptfoo, ragas, ...) and test suites (unit, integration, authz, security, opa). |
spec.dependencies | array | no | name, version range, optional. |
spec.configSchema | object | no | JSON Schema of the installation configuration. |
spec.domain, spec.namespace, spec.category, spec.publisher, spec.displayName, spec.security, spec.layout, spec.signedArtifact, spec.testFlags | no | Catalogue and security metadata of a pack. |
Lifecycle
enterprise-ai plugin covers create, validate, build, sign, publish and install of a Marketplace pack; the manifest follows contracts/v1/plugin-manifest.schema.json. Pack details are in the pack development guide.
enterprise-ai plugin create ./crm-pack --domain sales-crm --name crm-pack
enterprise-ai plugin validate ./crm-pack
enterprise-ai plugin build ./crm-pack --out dist
enterprise-ai plugin sign ./crm-pack --out dist --key cosign.key --signer acme
enterprise-ai plugin publish ./crm-pack --out dist --key cosign.key
build, sign and publish take the pack folder: the archive is rebuilt, reproducibly, in the --out folder (by
default dist inside the pack).
Steps
-
Create the pack. The scaffold is runnable and passes every gate. In the portal, the manifest of an OCI plugin is written in Developer Studio > Plugin builder.
enterprise-ai plugin create ./crm-pack --domain sales-crm --name crm-pack--domain: one ofbanking,cybersecurity,document-intelligence,finance,hr,it,legal,marketing,procurement,risk-compliance,sales-crm,support.Expected result: the created files are listed.
If it fails: exit code 1 means the folder exists; add
--force. -
Edit the manifest. Fill
plugin.yaml: requested permissions with a reason each, data protection, approvals, compatibility. See the pack development guide for each folder.Expected result: every scope used by an agent, a skill or a tool of the pack is requested.
If it fails: the next step lists the missing or unsafe permissions.
-
Validate. The same checks run again on the Control Plane at publication and installation.
enterprise-ai plugin validate ./crm-packExpected result: the pack is reported valid with its name and version.
If it fails: exit code 1 lists each error of the layout and of the manifest.
-
Build and sign.
buildwrites the reproducible archive, its SHA-256 digest and an SPDX SBOM.signsigns the archive digest and the digest of every SKILL.md, and writes the descriptor<name>-<version>.pack.jsonnext to the archive.enterprise-ai plugin build ./crm-pack --out distenterprise-ai plugin sign ./crm-pack --out dist --key cosign.key --signer acmeacme: the publisher name registered in the Marketplace.Expected result: the digest, the signer and the number of signed skills are printed.
If it fails: exit code 2 with "--key and --signer are required".
-
Publish.
publishruns the pack tests, the evaluations and the scan, stops on a failed gate, optionally pushes to an OCI registry with--oci, then calls POST /v1/marketplace/packages.enterprise-ai plugin publish ./crm-pack --out dist --key cosign.key --oci <harbor-host>/packs/crm-packExpected result: the package version is returned by the Marketplace.
If it fails: exit code 1 names the failed gate; an unsigned archive is refused before any call.
-
Install.
plugin installsends POST /v1/marketplace/installations: the preflight runs, then an approvalmarketplace.installis opened (quorum 2 when a sensitive permission is granted or inprod). Once approved, POST /v1/marketplace/installations/{installation_id}/apply creates the objects and runs a smoke test.enterprise-ai plugin install crm-pack --version 1.0.0 --env staging --grant crm.records.readExpected result: the approval id and the quorum are printed.
If it fails: 403
permission_unsafe, 422config_invalid, 422permission_not_requested, 409package_suspendedor 422preflight_failed. -
Register and install an OCI plugin. POST /v1/plugins verifies the signature of the image and records it; POST /v1/plugins/{name}/install renders the sandboxed deployment and its network policy. In the portal: Developer Studio > Plugin builder > Test > Read the status (GET /v1/plugins/{name}/status).
Expected result: status
installed,verified: trueand theruntime_classof the sandbox.If it fails: 403
plugin_unsigned, 403plugin_blocked, 422invalid_manifest. -
Upgrade or roll back. Raise
metadata.version, publish, then POST /v1/marketplace/installations/{installation_id}/upgrade; POST /v1/marketplace/installations/{installation_id}/rollback restores the previous version. An OCI plugin is updated with POST /v1/plugins while it is not installed.Expected result: the installation runs the new version after its approval and smoke test.
If it fails: 409
installation_state, 409rollback_unavailable, 422smoke_failed(the current version stays), 409plugin_installedfor an OCI plugin still installed. -
Suspend or remove. POST /v1/marketplace/installations/{installation_id}/status suspends or resumes an installation; POST /v1/marketplace/installations/{installation_id}/uninstall removes every object it created. An OCI plugin is removed with POST /v1/plugins/{name}/uninstall.
Expected result: status
suspendedoruninstalled.If it fails: 409
installation_stateor 409plugin_not_installed.
Installation
POST /v1/plugins registers a plugin, POST /v1/plugins/{name}/install installs it; on the Marketplace side, POST /v1/marketplace/preflight checks capabilities and configuration before POST /v1/marketplace/installations. See the Marketplace guide.
client.plugins.install("sap-connector-pack")
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
422 pack_requires_marketplace | A format: pack manifest was sent to POST /v1/plugins. | Publish it with enterprise-ai plugin publish and install it from the Marketplace. |
422 invalid_manifest | OCI digest differs from artifact.digest, egress_allowlist missing, or invalid sandbox limits. | Fix the field named in details. |
403 plugin_unsigned | The signature of the image is not verified at install. | Sign the image and register it again. |
403 plugin_blocked | The plugin is blocked. | Ask a security_officer why; publish a fixed version. |
409 plugin_installed | Update of an OCI plugin that is installed. | Uninstall it first. |
409 plugin_not_installed | Uninstall of a plugin that is not installed. | Read GET /v1/plugins/{name}/status. |
422 preflight_failed | A preflight check failed. | Run POST /v1/marketplace/preflight and read every check. |
403 permission_unsafe | The pack requests an unsafe scope. | Remove the scope from requestedPermissions. |
422 smoke_failed | The smoke test failed after apply. | The installation was rolled back; fix the pack and publish a new version. |
409 marketplace_version_exists | The version is already published. | Raise metadata.version. |