Building Plugins
Plugins extend a Stratum node with extra capabilities — custom protocol handlers, integrations, observability exporters, or specialised data-plane rules — without touching the core agent. This page is the practical guide to building, signing, and shipping your own plugin. To install one you already have, see Installing Plugins.
Every plugin is an Ed25519-signed .cenvero-plugin package. A node will only load a plugin signed by a developer certificate that Cenvero issued to you — so you don't manage any trust roots yourself; you just sign with your own key and the certificate we give you. You build and sign packages with the cnvstrpack tool.
How plugins run (sandboxed, out-of-process)
A plugin is a signed executable, not a shared library. The agent runs it as a supervised, unprivileged child process — never inside the agent and never as root:
- The agent verifies the full signature chain, scope, and revocation status _before_ it launches your executable. A bad package is rejected and the process is never started.
- Your plugin then runs as a separate process under a dedicated unprivileged user (
cenvero-str-plugin), in its own process group, with CPU / memory / open-file limits applied. It has no access to the agent's memory, private keys, configuration secrets, or root-owned files. - The only thing your plugin can do is talk to the agent over a small JSON protocol on its stdin/stdout, calling the capability-scoped host API the agent grants it (see Capabilities). Everything is deny-by-default: a host call you weren't granted is rejected and your plugin is terminated.
This means an over-scoped or malicious plugin cannot compromise the node — the worst it can do is misbehave inside its own sandbox and get restarted or killed.
1. Get the packer
Download cnvstrpack from the Releases page (it's listed alongside the agent). It's a single self-contained binary — no install needed.
cnvstrpack --help
2. Lay out your plugin
A plugin is a directory containing your entrypoint executable plus a manifest.json:
my-plugin/
├── manifest.json
└── entrypoint # your compiled binary (any language) — must be executable
{
"name": "my-plugin",
"version": "1.0.0",
"author": "Acme Corp",
"description": "What this plugin does",
"min_agent_version": "1.0.0",
"entrypoint": "entrypoint",
"requested_capabilities": ["log", "emit_event", "register_hook"],
"hooks": ["on:flow.new"],
"dependencies": []
}
entrypointis the executable the agent launches as your sandboxed child (defaults toentrypointif omitted). It can be written in any language; it just speaks the JSON protocol on stdin/stdout.requested_capabilitiesis the list of host-API functions your plugin needs. You only get the intersection of what you request and what your certificate's scope allows — request the minimum (see Capabilities).hooksare the data-plane hook points your plugin registers for. You may only register hooks you declared here.
On startup your entrypoint must: (1) send a handshake advertising its name/version/API and declared capabilities, (2) handle hook_invoke messages within the per-hook deadline, and (3) make host-API calls only for capabilities it was granted.
3. Become a developer + get your certificate
First, apply for developer access: in your account, choose Become a developer. Once an admin approves you, open your Developer portal at /account/developer.
Generate your signing keypair locally and keep the .key private:
cnvstrpack keygen -o mydev # writes mydev.key (secret) and mydev.pub
In the Developer portal, paste the contents of mydev.pub, choose a scope, and request a certificate — it is signed instantly. Download the resulting developer.cert and the plugin-intermediate.cert from the same page. Your private key never leaves your machine, and Cenvero's root/intermediate keys stay on our side — you only ever handle your own .key.
4. Pack & sign
cnvstrpack pack ./my-plugin \
--key mydev.key \
--devcert developer.cert \
--intcert plugin-intermediate.cert \
-o my-plugin-1.0.0.cenvero-plugin
cnvstrpack validates the manifest, archives the directory, signs it with your key, and embeds your developer certificate — producing a ready-to-ship my-plugin-1.0.0.cenvero-plugin.
Sanity-check it before sending:
cnvstrpack verify my-plugin-1.0.0.cenvero-plugin --pub mydev.pub
5. Ship it
Hand the .cenvero-plugin file to the node operator — they install it with one command (see Installing Plugins). The agent re-verifies the signature on load; a tampered or out-of-scope package is rejected with a clear error and never partially loaded.
Capabilities {#capabilities}
Your plugin can only call host functions it was granted. You request capabilities in requested_capabilities; the agent grants the intersection of your request and what your certificate's scope permits — it can never exceed the certificate. Any call to an ungranted function is rejected and your plugin is terminated.
The fixed set of host-API capabilities:
| Capability | What it lets your plugin do |
|---|---|
log | Write structured log lines to the agent log. |
emit_event | Publish an event onto the agent's event bus (tagged with your plugin name). |
get_config_value | Read a small, read-only subset of non-secret config values (e.g. node id, agent version). Never exposes API tokens or keys. |
register_hook | Register for a hook point — but only one you also declared in hooks. |
kv_get / kv_put | A small key/value scratch store scoped to your plugin — you cannot read or write another plugin's keys. |
Capability availability by scope:
any(public distribution):log,emit_event,get_config_value,register_hook.license:<serial>/hardware:<id>(bound to a specific deployment): the above pluskv_get/kv_put.
Request the least you need: a smaller capability set is easier to get approved and reduces blast radius.
Scopes {#scopes}
When Cenvero issues your developer certificate, it carries a scope that decides which nodes will accept your plugins. Pick the one that matches how you distribute:
| Scope | Use it for |
|---|---|
any | A general-purpose plugin you distribute publicly — runs on any licensed node. |
license:<serial> | A customer- or enterprise-specific plugin — runs only on nodes activated with that license. |
hardware:<id> | A one-off plugin pinned to a single machine. Get the node's id with cenvero-str-ctl node info. |
Scope is fixed at issuance; to change it, request a new certificate.
Dependencies & licensing
- If your
manifest.jsondeclares dependencies, the agent installs in dependency order automatically and rejects circular or unsatisfiable version constraints at install time — you don't manage load order. - Plugin installs are blocked while a node's license is in the frozen state; already-running plugins keep going. See Licensing.
See also
- Installing Plugins — install, list, verify, and remove on a node.
- CLI Reference — the
plugincommand group.